variable type rango number new float c# .net floating-point

c# - type - Float/precisión doble en modos de depuración/liberación



number c# (6)

De hecho, pueden diferir si el modo de depuración usa la FPU x87 y el modo de lanzamiento usa SSE para flotantes.

¿Las operaciones de punto flotante C # /. NET difieren en precisión entre el modo de depuración y el modo de liberación?


De hecho, pueden ser diferentes. De acuerdo con la especificación CLR ECMA:

Las ubicaciones de almacenamiento para números de coma flotante (estáticos, elementos de matriz y campos de clases) son de tamaño fijo. Los tamaños de almacenamiento admitidos son float32 y float64. En todas partes (en la pila de evaluación, como argumentos, como tipos de devolución y como variables locales), los números de coma flotante se representan utilizando un tipo de coma flotante interno. En cada caso, el tipo nominal de la variable o expresión es R4 o R8, pero su valor puede representarse internamente con un rango y / o precisión adicionales. El tamaño de la representación interna de coma flotante depende de la implementación, puede variar y debe tener una precisión al menos tan grande como la de la variable o expresión que se representa. Se realiza una conversión de ampliación implícita a la representación interna de float32 o float64 cuando esos tipos se cargan desde el almacenamiento. La representación interna suele ser el tamaño nativo del hardware, o según se requiera para la implementación eficiente de una operación.

Lo que esto básicamente significa es que la siguiente comparación puede ser o no igual:

class Foo { double _v = ...; void Bar() { double v = _v; if( v == _v ) { // Code may or may not execute here. // _v is 64-bit. // v could be either 64-bit (debug) or 80-bit (release) or something else (future?). } } }

Mensaje para llevar a casa: nunca verifique los valores flotantes para la igualdad.


Deberían ser iguales. Los números de coma flotante se basan en el estándar IEEE_754 .


En respuesta a la solicitud de Frank Krueger anterior (en comentarios) para una demostración de una diferencia:

Compile este código en gcc sin optimizaciones y -mfpmath = 387 (no tengo ninguna razón para pensar que no funcionaría en otros compiladores, pero no lo he probado). Luego, compílelo sin optimizaciones y -msse -mfpmath = sse.

La salida será diferente.

#include <stdio.h> int main() { float e = 0.000000001; float f[3] = {33810340466158.90625,276553805316035.1875,10413022032824338432.0}; f[0] = pow(f[0],2-e); f[1] = pow(f[1],2+e); f[2] = pow(f[2],-2-e); printf("%s/n",f); return 0; }



Esta es una pregunta interesante, así que hice un poco de experimentación. Usé este código:

static void Main (string [] args) { float a = float.MaxValue / 3.0f, b = a * a; if (a * a < b) { Console.WriteLine ("Less"); } else { Console.WriteLine ("GreaterEqual"); } }

usando DevStudio 2005 y .Net 2. Compilé como depuración y versión y examiné el resultado del compilador:

Release Debug static void Main (string [] args) static void Main (string [] args) { { 00000000 push ebp 00000001 mov ebp,esp 00000003 push edi 00000004 push esi 00000005 push ebx 00000006 sub esp,3Ch 00000009 xor eax,eax 0000000b mov dword ptr [ebp-10h],eax 0000000e xor eax,eax 00000010 mov dword ptr [ebp-1Ch],eax 00000013 mov dword ptr [ebp-3Ch],ecx 00000016 cmp dword ptr ds:[00A2853Ch],0 0000001d je 00000024 0000001f call 793B716F 00000024 fldz 00000026 fstp dword ptr [ebp-40h] 00000029 fldz 0000002b fstp dword ptr [ebp-44h] 0000002e xor esi,esi 00000030 nop float float a = float.MaxValue / 3.0f, a = float.MaxValue / 3.0f, 00000000 sub esp,0Ch 00000031 mov dword ptr [ebp-40h],7EAAAAAAh 00000003 mov dword ptr [esp],ecx 00000006 cmp dword ptr ds:[00A2853Ch],0 0000000d je 00000014 0000000f call 793B716F 00000014 fldz 00000016 fstp dword ptr [esp+4] 0000001a fldz 0000001c fstp dword ptr [esp+8] 00000020 mov dword ptr [esp+4],7EAAAAAAh b = a * a; b = a * a; 00000028 fld dword ptr [esp+4] 00000038 fld dword ptr [ebp-40h] 0000002c fmul st,st(0) 0000003b fmul st,st(0) 0000002e fstp dword ptr [esp+8] 0000003d fstp dword ptr [ebp-44h] if (a * a < b) if (a * a < b) 00000032 fld dword ptr [esp+4] 00000040 fld dword ptr [ebp-40h] 00000036 fmul st,st(0) 00000043 fmul st,st(0) 00000038 fld dword ptr [esp+8] 00000045 fld dword ptr [ebp-44h] 0000003c fcomip st,st(1) 00000048 fcomip st,st(1) 0000003e fstp st(0) 0000004a fstp st(0) 00000040 jp 00000054 0000004c jp 00000052 00000042 jbe 00000054 0000004e ja 00000056 00000050 jmp 00000052 00000052 xor eax,eax 00000054 jmp 0000005B 00000056 mov eax,1 0000005b test eax,eax 0000005d sete al 00000060 movzx eax,al 00000063 mov esi,eax 00000065 test esi,esi 00000067 jne 0000007A { { Console.WriteLine ("Less"); 00000069 nop 00000044 mov ecx,dword ptr ds:[0239307Ch] Console.WriteLine ("Less"); 0000004a call 78678B7C 0000006a mov ecx,dword ptr ds:[0239307Ch] 0000004f nop 00000070 call 78678B7C 00000050 add esp,0Ch 00000075 nop 00000053 ret } } 00000076 nop else 00000077 nop { 00000078 jmp 00000088 Console.WriteLine ("GreaterEqual"); else 00000054 mov ecx,dword ptr ds:[02393080h] { 0000005a call 78678B7C 0000007a nop } Console.WriteLine ("GreaterEqual"); } 0000007b mov ecx,dword ptr ds:[02393080h] 00000081 call 78678B7C 00000086 nop }

Lo que muestra lo anterior es que el código de coma flotante es el mismo tanto para la depuración como para la versión, el compilador elige la coherencia sobre la optimización. Aunque el programa produce el resultado incorrecto (a * a no es menor que b) es el mismo independientemente del modo de depuración / liberación.

Ahora, la Intel IA32 FPU tiene ocho registros de coma flotante, se podría pensar que el compilador usaría los registros para almacenar valores al optimizar en lugar de escribir en la memoria, mejorando así el rendimiento, algo así como:

fld dword ptr [a] ; precomputed value stored in ram == float.MaxValue / 3.0f fmul st,st(0) ; b = a * a ; no store to ram, keep b in FPU fld dword ptr [a] fmul st,st(0) fcomi st,st(0) ; a*a compared to b

pero esto se ejecutaría de manera diferente a la versión de depuración (en este caso, muestra el resultado correcto). Sin embargo, cambiar el comportamiento del programa dependiendo de las opciones de compilación es algo muy malo.

El código FPU es un área donde la elaboración manual del código puede superar significativamente al compilador, pero es necesario que conozcas cómo funciona la FPU.