Rendimiento flotante vs doble

91

Hice algunas pruebas de tiempo y también leí algunos artículos como este (último comentario), y parece que en la compilación de la versión, los valores flotantes y dobles toman la misma cantidad de tiempo de procesamiento.

¿Cómo es esto posible? Cuando el flotador es menos preciso y más pequeño en comparación con los valores dobles, ¿cómo puede el CLR duplicarse en el mismo tiempo de procesamiento?

Joan Venge
fuente
10
No creo que sea un duplicado exacto, ya que este pregunta la razón detrás de esto, mientras que el otro usuario pregunta si en realidad es más rápido, pero no necesariamente por qué,
Joan Venge
Supuestamente un duplicado exacto de ¿Son los dobles más rápidos que los flotantes en C #? (reclamado en 2009 por otro usuario).
Peter Mortensen

Respuestas:

155

En procesadores x86, al menos, floaty doublela FPU convertirá cada uno a un valor real de 10 bytes para su procesamiento. La FPU no tiene unidades de procesamiento separadas para los diferentes tipos de punto flotante que admite.

El antiguo consejo floates más rápido que el que se doubleaplicó hace 100 años cuando la mayoría de las CPU no tenían FPU incorporadas (y pocas personas tenían chips FPU separados), por lo que la mayor parte de la manipulación de punto flotante se realizaba en software. En estas máquinas (que funcionaban con vapor generado por los pozos de lava), era más rápido usar floats. Ahora, el único beneficio real de los floats es que ocupan menos espacio (lo que solo importa si tiene millones de ellos).

Papi
fuente
9
Quizás no hace 100 años ... Algunas FPU admiten el manejo nativo en niveles flotantes, dobles y de 80 bits y se ejecutarán más rápido en longitudes más cortas. Algunos realmente ejecutarán algunas cosas más lentamente en longitudes más cortas también ... :-)
Brian Knoblauch
4
Posible excepción: creo que el tiempo de las divisiones depende del número de bits (1 ciclo de reloj / 2 bits). Los tiempos que he hecho de flotación frente a doble división parecen coincidir con esto.
Neil Coffey
21
Advertencia para el código SIMD: dado que puede empacar 2 veces más flotantes que dobles en un registro SIMD (por ejemplo, SSE), operar con flotantes podría ser más rápido. Pero como es C #, es probable que eso no suceda.
Calyth
13
@P Daddy: Yo diría que la ventaja de espacio es importante en todos los niveles de la jerarquía de caché. Cuando su caché de datos de primer nivel tiene un tamaño de 16 KB y está procesando una matriz de 4000 números, flotar fácilmente podría ser más rápido.
Peter G.
4
@artificialidiot Nunca digas nunca;). SIMD es compatible con .NET desde 4.6
ghord
13

Tuve un pequeño proyecto en el que usé CUDA y puedo recordar que el flotador también era más rápido que el doble. Por una vez, el tráfico entre el Host y el Dispositivo es menor (el Host es la CPU y la RAM "normal" y el Dispositivo es la GPU y la RAM correspondiente allí). Pero incluso si los datos residen en el dispositivo todo el tiempo, es más lento. Creo que leí en alguna parte que esto ha cambiado recientemente o se supone que cambiará con la próxima generación, pero no estoy seguro.

Entonces, parece que la GPU simplemente no puede manejar la doble precisión de forma nativa en esos casos, lo que también explicaría por qué se usa generalmente GLFloat en lugar de GLDouble.

(Como dije, es solo por lo que puedo recordar, me encontré con esto mientras buscaba flotante frente a doble en una CPU).

Mene
fuente
6
Las GPU son animales totalmente diferentes a las FPU. Como otros mencionaron, el formato nativo de FPU es la precisión doble de 80 bits. Y eso es desde hace mucho tiempo. Sin embargo, las GPU se acercan a este campo con precisión simple. Es bien sabido que su rendimiento de DP FP (punto flotante de doble precisión) suele ser exactamente la mitad del rendimiento de SP FP. Parece que a menudo tienen unidades de punto flotante SP, y tienen que reutilizar la unidad para cubrir la doble precisión. Lo que produce exactamente dos ciclos en comparación con uno. Esa es una gran diferencia de rendimiento , que me sorprendió cuando me enfrenté a ella.
Csaba Toth
1
Algunos cálculos científicos requieren DP FP, y los principales fabricantes de GPU no anunciaron la penalización de rendimiento en torno a eso. Ahora ellos (AMD, nVidia) parecen mejorar un poco en ese tema de DP vs SP. Los muchos núcleos de Intel Xeon Phi contienen las FPU de Pentium, y observe que Intel enfatizó sus capacidades de doble precisión . Ahí es donde quizás realmente pueda competir con los monstruos GPGPU.
Csaba Toth
12

Sin embargo, todavía hay algunos casos en los que se prefieren los flotadores; con la codificación OpenGL, por ejemplo, es mucho más común usar el tipo de datos GLFloat (generalmente mapeado directamente a un float de 16 bits) ya que es más eficiente en la mayoría de las GPU que GLDouble.

Cruachan
fuente
3
¿Quizás debido a un mayor rendimiento de datos? Si tiene una matriz de números (z-buffer, etc.), el tamaño de los datos se vuelve más importante y evitar las conversiones entre flotante y doble acelera el manejo. Mi conjetura.
Lucero
2
Sin duda, rendimiento. Además, dado el contexto especializado, es poco probable que se obtenga algo visible al usar dobles sobre flotadores, entonces, ¿por qué desperdiciar la memoria, especialmente porque hay menos suministro en las GPU que en las CPU
Cruachan
1
Rendimiento y también el hecho de que SP FP (punto flotante de precisión simple) es más el formato nativo de las FPU internas de la GPU que DP FP (precisión doble). Vea mi comentario a la respuesta de @ Mene. Las GPU y las CPU FPU son animales muy diferentes, la FPU de la CPU está pensando en DP FP.
Csaba Toth
12

Depende del sistema de 32 o 64 bits . Si compila a 64 bits, el doble será más rápido. Compilado a 32 bits en 64 bits (máquina y sistema operativo) hizo flotar alrededor de un 30% más rápido:

    public static void doubleTest(int loop)
    {
        Console.Write("double: ");
        for (int i = 0; i < loop; i++)
        {
            double a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = Math.Sin(a);
            b = Math.Asin(b);
            c = Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    public static void floatTest(int loop)
    {
        Console.Write("float: ");
        for (int i = 0; i < loop; i++)
        {
            float a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = (float) Math.Sin(a);
            b = (float) Math.Asin(b);
            c = (float) Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    static void Main(string[] args)
    {
        DateTime time = DateTime.Now;
        doubleTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        time = DateTime.Now;
        floatTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        Thread.Sleep(5000);
    }
Azul amargo
fuente
2
¿Has considerado que ese 30% podría deberse a los yesos adicionales que usas?
Rasmus Damgaard Nielsen
@RasmusDamgaardNielsen Los moldes son parte del problema ya que Mathfunciona con double. Pero leíste mal mi publicación: mis pruebas me mostraron un mejor rendimiento.
Bitterblue
2
Los resultados publicados anteriormente son falsos. Mis pruebas muestran que en una máquina anterior de 32 bits con .NET 4.0 en modo Release, el rendimiento floaty el doubleson prácticamente idénticos. Menos del 0,3% de diferencia cuando se promedió en muchas pruebas independientes, donde cada prueba ejerció operaciones de multiplicación, división y suma en variables encadenadas consecutivamente (para evitar que las optimizaciones del compilador se interpusieran). Probé un segundo conjunto de pruebas con Math.Sin()y Math.Sqrt()y también obtuve resultados idénticos.
Salsa especial