문제

하 C#/.NET 부동 소수점 연산에서 차이가 정밀도 사이에 디버깅 모드와 릴리스 모드가 있습니까?

도움이 되었습니까?

해결책

그들은 실제로 다를 수 있습니다.에 따라 CLR ECMA 사양:

저장 위치에 대한 부동 소수점 숫자(정역학,배열 요소,그리고 필드 클래스)크기도 고정되어 있습니다.지원되는 스토리지 크기 float32 및 float64.다른 곳에서 (에서 평가택 인수,으로 돌아의 유형,그리고 지역 변수)부동 소수점 숫자를 표현하는 내장 부동 소수점 형식이어야 합니다.에서 각 이러한 인스턴스 명목상의 유형 변수 또는 표현은 하나 R4 나 R8 지만,그 값을 표현할 수 있는 내부적으로 추가적인 범위 및/또는 정밀도입니다.의 크기 내장 부동 소수점 representation 은 구현에 따라 다를 수 있습니다 하여 정밀도가 최소한 하는 변수의 또는 식 표현되고있다.인 암시적으로 확대 변환기 내부 표현에서 float32 또 float64 수행할 때 사람들 형식 로드 저장소에서.이 내부 표현은 일반적으로 기본 크기는 하드웨어,또는 으로 필요한 효율 의 구현하는 작업입니다.

이것이 기본적으로 의미는 다음과 같은 비교되지 않을 수 있 같:

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?).
    }
  }
}

집에 가져갈 메시지:지 확인 부동 값에 대한 평등.

다른 팁

이것은 흥미로운 질문을 했어요 그래서 약간의 실험을.이 코드:

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");
  }
}

사용 DevStudio2005.Net2.나는 컴파일한 모두로 디버깅하고 방출 및 검토 출력의 컴파일러:

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              
                                                              }

무엇을 위에 보여줍은 부동 소수점 코드가 동일한 모두에 대한 디버그 및 릴리스 컴파일러를 선택하고 일관성을 통해 최적화할 수도 있습니다.하지만 프로그램을 생산하는 잘못된 결과(a*a is not less than b)그것은 관계없이 동일하는 디버그/릴리스 모드입니다.

지금,Intel IA32FPU 은 여덟 부동 소수점 레지스터는,당신은 생각하는 컴파일러를 사용하여 레지스터 값을 저장할 때 최적화보다는 메모리에 쓰고,따라서 성능을 향상,무언가의 라인을 따라:

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

그러나 이것이 다르게 실행하는 디버 버전(이 경우 정확한 결과가 표시).그러나 변경하는 행동에 따라 프로그램의 구축하는 옵션은 아주 나쁜 것입니다.

FPU 코드는 하나의 영역입니다 손으로 만들어 코드는 크게 밖으로 수행하는 컴파일러,하지만 당신은 당신이 필요하 주위에 당신의 머리를하는 방식 FPU 작동합니다.

사실,그들은 다를 수 있습니다면 디버깅 모드를 사용하 x87FPU 및 릴리스 모드로 사용하여 SSE for float-ops.

에 대응하여 프랭크 크루거의 요청이 위에서(주석)유의한 차이가:

이 코드를 컴파일에서 gcc 가 없는 최적화-mfpmath=387(나는 이유가 없다 생각하고 그것은 작동하지 않을 것에서 다른 컴파일러,하지만은 이렇게 말했습니다.) 그런 다음 그것을 컴파일없이 최적화-msse-mfpmath=sse.

출력 차이가 있습니다.

#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;
}

여기에 간단한 예제는 결과뿐만 아니라 다를 디버깅 모드와 릴리스 모드지만,이 방법으로는 그들이 그렇게 여부에 따라 사용 x86 또는 x84 플랫폼으로:

Single f1 = 0.00000000002f;
Single f2 = 1 / f1;
Double d = f2;
Console.WriteLine(d);

이 기록은 다음과 같은 결과를 생성합니다.

            Debug       Release
x86   49999998976   50000000199,7901
x64   49999998976   49999998976

빠른 모습에서 분해(디버그->Windows>분해 Visual Studio)을 제공하는 일부에 대한 힌트를 여기에 무슨 일이 일어나.X86 경우:

Debug                                       Release
mov         dword ptr [ebp-40h],2DAFEBFFh | mov         dword ptr [ebp-4],2DAFEBFFh  
fld         dword ptr [ebp-40h]           | fld         dword ptr [ebp-4]   
fld1                                      | fld1
fdivrp      st(1),st                      | fdivrp      st(1),st
fstp        dword ptr [ebp-44h]           |
fld         dword ptr [ebp-44h]           |
fstp        qword ptr [ebp-4Ch]           |
fld         qword ptr [ebp-4Ch]           |
sub         esp,8                         | sub         esp,8 
fstp        qword ptr [esp]               | fstp        qword ptr [esp]
call        6B9783BC                      | call        6B9783BC

특히,우리는 우리 무리의 겉으로 중복되는"저장하는 값에서 부동 소수점에 등록한 메모리로 다시 메모리에서 부동점"에 최적화되었다 릴리스 모드에서.그러나,두 개의 지침

fstp        dword ptr [ebp-44h]  
fld         dword ptr [ebp-44h]

는 충분한 값을 변경하에서 x87 등록에서+5.0000000199790138e+0010 를+4.9999998976000000e+0010 중 하나로 확인할 수 있습을 통해 단계별로 분해 및 조사하는 값의 관련 레지스터(디버그->Windows->등록한 다음 마우스 오른쪽 버튼을 클릭하고"확인 부동 소수점").

에 대한 이야기 64 은 격렬하게 다릅니다.우리는 여전히 같은 최적화를 제거하는 몇 가지 지침이지만,이번에 모든 것에 의존하여 SSE 그 128 비트 레지스터와 전용 지시 설정:

Debug                                        Release
vmovss      xmm0,dword ptr [7FF7D0E104F8h] | vmovss      xmm0,dword ptr [7FF7D0E304C8h]  
vmovss      dword ptr [rbp+34h],xmm0       | vmovss      dword ptr [rbp-4],xmm0 
vmovss      xmm0,dword ptr [7FF7D0E104FCh] | vmovss      xmm0,dword ptr [7FF7D0E304CCh]
vdivss      xmm0,xmm0,dword ptr [rbp+34h]  | vdivss      xmm0,xmm0,dword ptr [rbp-4]
vmovss      dword ptr [rbp+30h],xmm0       |
vcvtss2sd   xmm0,xmm0,dword ptr [rbp+30h]  | vcvtss2sd   xmm0,xmm0,xmm0 
vmovsd      qword ptr [rbp+28h],xmm0       |
vmovsd      xmm0,qword ptr [rbp+28h]       |
call        00007FF81C9343F0               | call        00007FF81C9343F0 

기 때문에,여기에 SSE 단위 방지를 사용하여 높은 정밀도를 보다 정밀도 단 하나 내부적으로(잠 x87 단위 않습니다)우리는 우리와 끝까지"정밀도 단 하나-틱"의 결과 86 경우에 관계없이 최적화를 달성할 수 있습니다.실제로 중 하나를 찾(사용하도록 설정한 후 SSE 등록 Visual Studio 레지스터 개요)그 이후 vdivss,XMM0 포함 0000000000000000-00000000513A43B7 는 정확하게 49999998976 에서 전입니다.

모두 차트에서 저를 연습합니다.게다가 보여주는 하나 결코 비교 평등의 부동 소수점 이 예제에서는 또한 없다는 것을 보여줍의 여전히 어셈블리에서 디버깅 높은 수준의 언어는 C#같은 순간을 부인합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top