C#/.NET 부동 소수점 연산의 디버그 모드와 릴리스 모드의 정밀도는 서로 다릅니 까?디버그/릴리스 모드의 부동 소수점/이중 정밀도
답변
그들은 참으로 다를 수있는 다른 것입니다 무슨 짓을했는지에 말하는 기사의 몇 가지를 발견했다. CLR은 ECMA 사양에 따르면, 부동 소수점 숫자
저장 위치 (정적, 배열 요소 및 클래스 필드 하는) 고정 된 크기이다. 지원되는 저장 장치 크기는 float32 및 float64입니다. 다른 곳에서는 (평가 스택에서는 인수로 반환 유형으로, 로컬 변수로) 부동 소수점 숫자는 내부 부동 소수점 유형을 사용하여 나타냅니다. 이러한 경우 변수 또는 표현식의 공칭 유형은 R4 또는 R8이지만 그 값은 내부적으로 및/또는 정밀도가있는 으로 표시 될 수 있습니다. 내부 부동 소수점 표현 의 크기는 구현에 따라 다르며 과 다를 수 있으며 변수의 값이 인 표현식이 표시 될 때 최소한 만큼 큰 정밀도를 가져야합니다. 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?). } } }
테이크 가정 메시지 :이 기본적으로 의미
는 다음 비교거나 같아야하지 않을 수 있다는 것이다 평등을위한 부동 값을 확인하지 않습니다.
DEBUG vs RELEASE 빌드 구성과 아무 관계가 없습니다 ... –
생성 된 IL은 같지만 ... 디버그로 표시된 어셈블리를 다룰 때 JITter는 덜 공격적입니다. 릴리스 빌드는 더 많은 부동 값을 80 비트 레지스터로 이동시키는 경향이 있습니다. 디버그 빌드는 64 비트 메모리 저장소에서 직접 읽는 경향이 있습니다. – stusmith
생성 된 IL이 같지 않을 수 있습니다. 디버그 모드는 중단 점이 가능한지 확인하기 위해 nop를 삽입합니다. 또한 해제 모드가 불필요하다고 판단하는 임시 변수를 의도적으로 유지 관리 할 수도 있습니다. – ShuggyCoUk
동일해야합니다. 부동 소수점 숫자는 IEEE_754 standard을 기준으로합니다.
디버그 모드에서 x87 FPU를 사용하고 릴리스 모드에서 float-ops에 SSE를 사용하면 실제로 다를 수 있습니다.
더 최적화를 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;
}
질문은 C#/.Net에 관한 것이 었습니다. 귀하의 예제는 C + +/네이티브 코드입니다. –
어쨌든 SSE 대 x87 FPU의 정밀도가 당신이 부르는 언어에 따라 다르다는 것을 나는 의심한다! –
C#으로 직접 변환하면 Visual Studio 2013에서 x86 및 x64에 대해 다른 결과가 나타납니다. x86 CLR은 x87 FPU를 사용하고 x64 CLR은 SSE를 사용합니다. – Asik
고마워 나는 수레의 행동이 릴리스 모드
http://blogs.msdn.com/davidnotario/archive/2005/08/08/449092.aspx
이것은 흥미로운 질문입니다. 그래서 나는 약간의 실험을했습니다.모두 디버그로 컴파일 및 해제 DevStudio와 2005 년과 닷넷 2.를 사용하여
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");
}
}
및 컴파일러의 출력 검사 :이 코드를 사용
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는 b보다 작지 않음) 디버그/릴리스 모드에 관계없이 동일합니다.
이제 인텔 IA32 FPU 여덟 개 부동 소수점 레지스터를 가지고, 당신은 최적화가 아닌 메모리에 기록하는, 따라서의 라인을 따라 뭔가를 성능을 개선 할 때 컴파일러가 값을 저장 레지스터를 사용하는 것이라고 생각 :
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 작동 방식에 대해 머리를 숙여 야합니다.
- 1. 부동 소수점 정밀도
- 2. 부동 소수점 정밀도
- 3. 파이썬 배열의 부동 소수점 정밀도
- 4. 단 정밀도 부동 소수점 사용
- 5. 단 정밀도 부동 소수점 표현에서 반 정밀도 부동 소수점으로 숫자 변환
- 6. qnorm/pnorm에 부동 소수점 정밀도 추가?
- 7. IEEE-754 형식에 따라 16 진수 값을 단 정밀도 부동 소수점 숫자 및 이중 정밀도 부동 소수점 숫자로 변환하는 방법
- 8. Python의 max()를 사용하는 동안 부동 소수점 정밀도
- 9. IEEE 754로 변환 단 정밀도 부동 소수점 형식 도움말
- 10. 일부 부동 소수점 정밀도 및 숫자 제한 질문
- 11. .net의 임의 정밀도 부동 유형입니다. 그것을 허락하는 어떤 도서관?
- 12. 부동 소수점 값 동등성 테스트 : "정밀도"상수의 표준 이름이 있습니까?
- 13. Javascript (float32)의 단 정밀도 부동 소수점 에뮬레이션
- 14. python에서 단 정밀도 부동 소수점을 에뮬레이트하는 올바른 방법은 무엇입니까?
- 15. Vala에 대한 큰 정수 및 임의/다중 정밀도 부동 소수점
- 16. 부동 소수점 등가성?
- 17. 기계 정밀도
- 18. MATLAB 정밀도
- 19. 정밀도 설정
- 20. 시계의 정밀도
- 21. DATETIME2 정밀도
- 22. .NET에서 단 정밀도 연산 연산?
- 23. 스핑크스 부동 소수점 서식
- 24. 자바 스크립트 큰 정수 때문에 정밀도? (왜?)
- 25. 혼합 정밀도 수치 알고리즘 분석에 관한 기사?
- 26. 파이썬에서 바이트를 부동 소수점 숫자로 변환
- 27. 숫자 정밀도 문제는 XML
- 28. 십진수 정밀도 문제 DbParameter
- 29. UITextField 정밀도 설정
- 30. Spring queryForLong - 정밀도 상실
왜 다른가? –
네, 당신의 사고 과정을 찾는 것에 관심이 있습니다. –
질문은 디버그와 릴리스의 차이점에 대한 것입니다. 릴리스 버전은 RAM보다 정밀도가 높은 레지스터 인 FPU = 80bit, double = 64bit, float = 32bit를 사용한다고 생각할 것입니다. – Skizz