C #에서 부동 소수점 수학이 일관됩니까? 할 수 있습니까?


155

아니요, 이것은 또 다른 "왜 (1 / 3.0) * 3! = 1" 질문 이 아닙니다 .

최근에 부동 소수점에 대해 많이 읽었습니다. 특히, 동일한 계산이 다른 아키텍처 또는 최적화 설정에서 다른 결과제공 할 수있는 방법 .

재생을 저장하거나 P2P 네트워크로 연결된 비디오 게임 (서버-클라이언트와 달리)의 문제로, 모든 클라이언트가 프로그램을 실행할 때마다 정확히 동일한 결과를 생성합니다-하나의 작은 불일치 부동 소수점 계산은 다른 컴퓨터에서 (또는 동일한 컴퓨터에서 ) 게임 상태가 크게 달라질 수 있습니다 !

이것은 일부 프로세서 (즉, x86)가 배 확장 정밀도를 사용하기 때문에 IEEE-754 를 "따르는"프로세서에서도 발생합니다 . 즉, 80 비트 레지스터를 사용하여 모든 계산을 수행 한 다음 64 비트 또는 32 비트로 잘라내어 계산에 64 비트 또는 32 비트를 사용하는 머신과 다른 반올림 결과를 가져옵니다.

온라인 에서이 문제에 대한 몇 가지 솔루션을 보았지만 C #이 아닌 C ++에 대한 모든 솔루션을 보았습니다.

  • (Windows), (Linux?) 또는 (BSD)를 double사용하여 배정 밀도 모드를 비활성화합니다 (모든 계산에서 IEEE-754 64 비트를 사용하도록 )._controlfp_s_FPU_SETCWfpsetprec
  • 항상 동일한 최적화 설정으로 동일한 컴파일러를 실행하고 모든 사용자에게 동일한 CPU 아키텍처가 있어야합니다 (플랫폼 간 재생 없음). 내 "컴파일러"는 실제로 JIT이므로 프로그램이 실행될 때마다 다르게 최적화 될 수 있기 때문에 이것이 가능하지 않다고 생각합니다.
  • 고정 소수점 연산, 그리고 피할 사용 floatdouble모두를. decimal이 목적으로 작동하지만 훨씬 느려질 것이며 System.Math그것을 지원 하는 라이브러리 함수는 없습니다.

그래서 이것은 C #에서도 문제가됩니까? 모노 만 아닌 Windows 만 지원하려면 어떻게해야합니까?

그렇다면 프로그램을 정상적인 배정도로 실행하도록 강제 할 수있는 방법이 있습니까?

그렇지 않은 경우 부동 소수점 계산을 일관성있게 유지 하는 데 도움이되는 라이브러리가 있습니까?


나는 본 적이 이 질문을 하지만, 모든 답은 하나 해결책으로 문제를 반복, 또는 옵션하지 않은 "무시"말했다. 나는 gamedev에 대해 비슷한 질문을 했지만 (청중들 때문에) 대부분의 답변은 C ++을 향한 것으로 보입니다.
BlueRaja-대니 Pflughoeft

1
하지 대답,하지만 난 당신이 대부분의 영역에서 모든 공유 상태가 결정하고, 그 때문에 더 큰 성능 저하가없는 방식으로 시스템을 설계 할 수있어
driushkin

1
@Peter .net에 대한 빠른 부동 소수점 에뮬레이션에 대해 알고 있습니까?
코드 InChaos

1
Java가이 문제로 고통 받습니까?
Josh

3
@Josh : Java에는 strictfp키워드가 있으므로 확장 된 크기가 아닌 지정된 크기 ( float또는 double)로 모든 계산을 수행해야합니다 . 그러나 Java는 여전히 IEE-754 지원에 많은 문제점이 있습니다. IEE-754를 잘 지원하는 프로그래밍 언어는 거의 없습니다.
porges

답변:


52

.net에서 일반 부동 소수점을 결정적으로 만드는 방법은 없습니다. JITter는 다른 플랫폼 (또는 다른 버전의 .net)에서 다르게 동작하는 코드를 작성할 수 있습니다. 따라서 float결정적 .net 코드에서 normal s를 사용할 수 없습니다.

내가 고려한 해결 방법 :

  1. C #에서 FixedPoint32를 구현하십시오. 이것이 너무 어렵지는 않지만 (반쯤 완성 된 구현이 있습니다) 매우 작은 범위의 값은 사용하기가 성가 시게합니다. 항상주의를 기울여야하므로 오버 플로우 나 정밀도가 떨어질 수 있습니다. 결국 나는 정수를 직접 사용하는 것보다 쉽지 않다는 것을 알았습니다.
  2. C #에서 FixedPoint64를 구현하십시오. 나는 이것이 오히려 어렵다는 것을 알았다. 일부 연산의 경우 128 비트의 중간 정수가 유용합니다. 그러나 .net은 그러한 유형을 제공하지 않습니다.
  3. 사용자 정의 32 비트 부동 소수점을 구현하십시오. BitScanReverse 내장 함수가 없으면이를 구현할 때 몇 가지 문제가 발생합니다. 그러나 현재 이것이 가장 유망한 길이라고 생각합니다.
  4. 수학 연산에는 기본 코드를 사용하십시오. 모든 수학 연산에서 델리게이트 호출의 오버 헤드가 발생합니다.

방금 32 비트 부동 소수점 수학의 소프트웨어 구현을 시작했습니다. 내 2.66GHz i3에서 초당 약 7 천만 더하기 / 곱하기를 할 수 있습니다. https://github.com/CodesInChaos/SoftFloat . 분명히 여전히 매우 불완전하고 버그가 있습니다.


2
에 "무제한"이 기본 int로서 아니지만 빠른 속도로 사용할 수 BigInteger를 정수 크기 또는 긴 그것이 거기가 .NET (나는 생각하지만, C #에서 사용할 수있는 F 번호 생성) 제공 등의 형태 않도록
룬 FS

또 다른 옵션은 .NET 용 GNU MP 래퍼입니다 . GNU 다중 정밀도 라이브러리 를 감싸는 래퍼입니다. "무한"정밀 정수, 유리수 (분수) 및 부동 소수점 숫자를 지원합니다.
Cole Johnson

2
이 중 하나를 수행하려면 decimal훨씬 간단하기 때문에 먼저 시도해 볼 수도 있습니다 . 당면한 과제에 비해 너무 느리다면 다른 접근법도 고려해야 할 가치가 있습니다.
Roman Starkov

부동 소수점이 결정적인 특별한 경우에 대해 배웠습니다. 설명 : 곱셈 / 나눗셈의 경우 FP 숫자 중 하나가 2의 거듭 제곱 (2 ^ x)이면 계산 중에 유효 / 가수가 변경되지 않습니다. 지수 만 변경됩니다 (포인트가 이동합니다). 따라서 반올림은 발생하지 않습니다. 결과는 결정적입니다.
지그재그

예 : 2 ^ 32와 같은 숫자는 (지수 : 32, 가수 : 1)로 표시됩니다. 이것을 다른 float (exp, man)과 곱하면 결과는 (exp + 32, man * 1)입니다. 나누기의 결과는 (expo-32, man * 1)입니다. 가수에 1을 곱해도 가수가 변경되지 않으므로 비트 수는 중요하지 않습니다.
지그재그

28

C # 사양 (§4.1.6 부동 소수점 유형)에서는 특히 결과보다 높은 정밀도를 사용하여 부동 소수점 계산을 수행 할 수 있습니다. 따라서 아니요, .Net에서 직접 계산을 결정할 수 있다고 생각하지 않습니다. 다른 사람들은 다양한 해결 방법을 제안 했으므로 시도해 볼 수 있습니다.


9
방금 컴파일 된 어셈블리를 배포하는 경우 C # 사양이 실제로 중요하지 않다는 것을 깨달았습니다. 소스 호환성을 원하는 경우에만 중요합니다. 실제로 중요한 것은 CLR 사양입니다. 그러나 나는 그것이 C # 보장만큼 약하다는 것이 확실하다고 확신합니다.
코드 InChaos

double작업 후 원치 않는 비트를 제거하여 일관된 결과를 생성 한 후 매번 캐스팅하지 않습니까?
IllidanS4는 Monica를

2
@ IllidanS4 나는 그것이 일관된 결과를 보장한다고 생각하지 않습니다.
svick

14

다음 페이지는 그러한 작업의 절대 이식성이 필요한 경우에 유용 할 수 있습니다. 부동 소수점 연산을 에뮬레이트하는 소프트웨어를 포함하여 IEEE 754 표준의 구현을 테스트하기위한 소프트웨어에 대해 설명합니다. 그러나 대부분의 정보는 C 또는 C ++에만 해당됩니다.

http://www.math.utah.edu/~beebe/software/ieee/

고정 점에 대한 참고 사항

이진 고정 소수점 숫자는 다음 네 가지 기본 산술 연산에서 알 수 있듯이 부동 소수점 대신 사용할 수 있습니다.

  • 덧셈과 뺄셈은 간단합니다. 정수와 같은 방식으로 작동합니다. 그냥 더하거나 빼세요!
  • 두 개의 고정 소수점 수를 곱하려면 두 수를 곱한 다음 정의 된 소수 비트 수만큼 오른쪽으로 이동합니다.
  • 두 개의 고정 소수점 수를 나누려면 피제수를 정의 된 소수 비트 수만큼 왼쪽으로 이동 한 다음 제수로 나눕니다.
  • 이 백서의 4 장 에는 이진 고정 소수점 수 구현에 대한 추가 지침 있습니다.

이진 고정 소수점 숫자는 int, long 및 BigInteger와 같은 정수 데이터 유형과 비 CLS 호환 유형 uint 및 ulong에서 구현 될 수 있습니다.

다른 답변에서 제안한 것처럼 테이블의 각 요소가 이진 고정 소수점 수인 조회 테이블을 사용하면 사인, 코사인, 제곱근 등과 같은 복잡한 함수를 구현할 수 있습니다. 룩업 테이블이 고정 소수점 수보다 세분화되지 않은 경우 룩업 테이블 세분화의 절반을 입력에 추가하여 입력을 반올림하는 것이 좋습니다.

// Assume each number has a 12 bit fractional part. (1/4096)
// Each entry in the lookup table corresponds to a fixed point number
//  with an 8-bit fractional part (1/256)
input+=(1<<3); // Add 2^3 for rounding purposes
input>>=4; // Shift right by 4 (to get 8-bit fractional part)
// --- clamp or restrict input here --
// Look up value.
return lookupTable[input];

5
sourceforge 또는 github와 같은 오픈 소스 코드 프로젝트 사이트에 업로드해야합니다. 이를 통해 쉽게 찾고, 기여하기 쉽고, 이력서에 쉽게 넣을 수 있습니다. 또한 몇 가지 소스 코드 팁 (무시할 수 있음) : 상수 const대신 사용 static하여 컴파일러에서 최적화 할 수 있습니다. 멤버 함수를 정적 함수보다 선호합니다 (따라서 myDouble.LeadingZeros()대신에 호출 할 수 있습니다 IntDouble.LeadingZeros(myDouble)). 한 글자로 된 변수 이름을 피하십시오 ( MultiplyAnyLength예를 들어, 9
개가 있으므로

사용주의 unchecked와 비 CLS 규격과 같은 종류의 ulong, uint그래서 그들이 실제로 할 수 있습니다 사용하여, 그들이 그렇게 거의 사용되지 않습니다 때문에 JIT가 공격적를 최적화하지 않습니다 - 등 속도 목적으로 느린 같은 일반적인 유형을 사용하는 것보다 long하고 int. 또한 C #에는 연산자 오버로드있으므로이 프로젝트에서 큰 이점을 얻을 수 있습니다. 마지막으로, 관련된 단위 테스트가 있습니까? 그 작은 일들, 놀라운 직업 피터 외에 , 이것은 엄청나게 인상적입니다!
BlueRaja-대니 Pflughoeft

의견 주셔서 감사합니다. 코드에서 단위 테스트를 수행합니다. 그러나 지금은 릴리스하기에는 너무 광범위합니다. 여러 테스트를보다 쉽게 ​​작성할 수 있도록 단위 테스팅 도우미 루틴도 작성합니다. 완료되면 코드를 Java로 변환 할 계획이 있으므로 현재 과부하 연산자를 사용하지 않습니다.
Peter O.

2
재미있는 것은 블로그에 글을 올렸을 때 블로그가 자신의 블로그라는 것을 알지 못했습니다. 방금 Google+를 사용해보기로 결정했으며 C #에서 블로그 항목을 제안했습니다. 그래서 저는 "두 사람이 동시에 그런 것을 쓰기 시작하는 것은 얼마나 놀라운 우연의 일치"라고 생각했습니다. 그러나 물론 우리는 같은 방아쇠를 가졌습니다 :)
CodesInChaos

1
왜 이것을 Java로 포팅해야합니까? Java는 이미를 통해 결정 론적 부동 소수점 수학을 보장했습니다 strictfp.
안티몬

9

이것이 C #의 문제입니까?

예. 다른 아키텍처로 인해 부동 소수점 표현의 부정확성 등의 프레임 속도 다른이 편차로 이어질 수 걱정거리를 - 그들은이 경우에도 동일한 (하나의 기계에 느린 GPU를 제외한 예를 들어 동일한 아키텍처) 부정확.

System.Decimal을 사용할 수 있습니까?

당신이 할 수없는 이유는 없지만 개가 느립니다.

프로그램을 배정도로 실행하는 방법이 있습니까?

예. CLR 런타임을 직접 호스팅하십시오 . CorBindToRuntimeEx를 호출하기 전에 모든 nessecary 호출 / 플래그 (부동 소수점 산술의 동작을 변경하는)를 C ​​++ 응용 프로그램으로 컴파일하십시오.

부동 소수점 계산을 일관성있게 유지하는 데 도움이되는 라이브러리가 있습니까?

내가 아는 한에서는 아니다.

이 문제를 해결하는 다른 방법이 있습니까?

전에이 문제를 해결했지만 아이디어는 QNumbers 를 사용하는 입니다. 그것들은 고정 소수점 형태의 실수입니다. 기수 -10 (10 진수)의 고정 소수점이 아닌 기수 -2 (이진수); 이 때문에 그것들의 수학적 프리미티브 (add, sub, mul, div)는 순진한 base-10 고정 점보다 훨씬 빠릅니다. 특히 n두 값이 같은 경우 (귀하의 경우). 또한 통합되어 있기 때문에 모든 플랫폼에서 명확한 결과를 얻을 수 있습니다.

프레임 속도는 여전히 이것에 영향을 미칠 수 있지만 동기화 지점을 사용하여 나쁘지 않고 쉽게 수정됩니다.

QNumber에 더 많은 수학적 함수를 사용할 수 있습니까?

예, 이것을하기 위해 십진수를 왕복합니다. 또한 trig (sin, cos) 함수에 룩업 테이블 을 사용해야 합니다. 그것들은 실제로 다른 플랫폼에서 다른 결과를 줄 수 있으므로 올바르게 코딩하면 QNumber를 직접 사용할 수 있습니다.


3
프레임 속도 문제가 무엇인지 확실하지 않습니다. 디스플레이 프레임 속도와 같은지 여부와 상관없이 고정 업데이트 속도 (예 : 여기 참조)를 원할 것 입니다. 모든 기계에서 부정확성이 동일한 한 우리는 좋습니다. 나는 당신의 세 번째 대답을 전혀 이해하지 못합니다.
BlueRaja-대니 Pflughoeft

@BlueRaja : 대답 "프로그램을 배정도로 실행하는 방법이 있습니까?" 사용자 셸리 버터 플라이의 답변에서 알 수 있듯이 전체 공용 언어 런타임을 다시 구현하거나 매우 복잡하거나 C # 응용 프로그램에서 C ++ DLL에 대한 기본 호출을 사용합니다. 내 대답에서 알 수 있듯이 "QNumbers"는 단지 이진 고정 소수점 숫자로 생각하십시오 (지금까지는 이진 고정 소수점 숫자가 "QNumbers"라고 표시되지 않았습니다).
Peter O.

@Pieter O. 런타임을 다시 구현할 필요가 없습니다. 회사에서 작업하는 서버는 CLR 런타임을 네이티브 C ++ 응용 프로그램으로 호스팅합니다 (SQL Server도 마찬가지). Google CorBindToRuntimeEx를 제안합니다.
Jonathan Dickinson

@BlueRaja 그것은 해당 게임에 따라 다릅니다. AOE 알고리즘은 인공 지연 시간을 도입하므로 모든 게임에 고정 프레임 속도 단계를 적용하는 것은 실행 가능한 옵션이 아닙니다. 예를 들어 FPS에서는 허용되지 않습니다.
Jonathan Dickinson

1
@ 조나단 :이 만 입력을 보내는 피어 - 투 - 피어 게임에서만 문제입니다 -이 들어, 고정 갱신 율을 가지고. 대부분의 FPS는 이와 같이 작동하지 않지만 일부는 반드시 고정 업데이트 속도를 갖습니다. 이 질문을 참조하십시오 .
BlueRaja-대니 Pflughoeft

6

이 약간 오래된 MSDN 블로그 항목에 따르면 JIT는 부동 소수점에 SSE / SSE2를 사용하지 않으며 x87입니다. 그 때문에 언급했듯이 모드와 플래그에 대해 걱정해야하며 C #에서는 제어 할 수 없습니다. 따라서 정상적인 부동 소수점 연산을 사용한다고해서 프로그램의 모든 기계에서 동일한 결과가 보장되는 것은 아닙니다.

배정 밀도의 정확한 재현성을 얻으려면 소프트웨어 부동 소수점 (또는 고정 소수점) 에뮬레이션을 수행해야합니다. 이 작업을 수행하는 C # 라이브러리를 모르겠습니다.

필요한 작업에 따라 단 정밀도로 벗어날 수 있습니다. 아이디어는 다음과 같습니다.

  • 관심있는 모든 값을 단 정밀도로 저장
  • 작업을 수행하려면
    • 입력을 배정도로 확장
    • 배정도로 조작하다
    • 결과를 단 정밀도로 다시 변환

x87의 큰 문제는 정밀도 플래그와 레지스터가 메모리에 유출되었는지 여부에 따라 53 비트 또는 64 비트 정확도로 계산이 수행 될 수 있다는 것입니다. 그러나 많은 작업에서 높은 정밀도로 작업을 수행하고 낮은 정밀도로 반올림하면 정답이 보장되므로 모든 시스템에서 정답이 동일하게 보장됩니다. 어느 쪽이든 정답을 보장하기에 충분한 정밀도를 가지므로 여분의 정밀도를 얻는 지 여부는 중요하지 않습니다.

이 체계에서 작동 해야하는 연산 : 더하기, 빼기, 곱하기, 나누기, sqrt. sin, exp 등과 같은 것은 작동하지 않습니다 (결과는 일반적으로 일치하지만 보장은 없습니다). "이중 반올림은 무해합니까?" ACM 참조 (유료 등록 요구)

도움이 되었기를 바랍니다!


2
또한 .NET 5 또는 6 또는 42가 더 이상 x87 계산 모드를 사용하지 않을 수도있는 문제입니다. 표준에 필요한 것은 없습니다.
Eric J.

5

다른 답변에서 이미 언급했듯이 : 예, 이것은 순수한 Windows를 유지하는 경우에도 C #의 문제입니다.

해결책에 관해서 : 내장 BigInteger클래스를 사용하고 그러한 수의 계산 / 저장에 공통 분모를 사용하여 모든 계산을 정의 된 정밀도로 스케일링 하면 문제를 줄일 수 있습니다 (그리고 약간의 노력 / 성능 저하로) .

OP의 요청에 따라 성능과 관련하여 :

System.Decimal부호는 1 비트, 96 비트 정수 및 "스케일"(소수점이있는 위치)로 숫자를 나타냅니다. 모든 계산에서이 데이터 구조에서 작동해야하며 CPU에 내장 된 부동 소수점 명령어를 사용할 수 없습니다.

BigInteger"솔루션"비슷한 않습니다 - 당신은 아마 당신이 80 비트 또는 정밀도의 240 개 비트를 원하는 ... 당신이 /가 필요합니다 얼마나 많은 숫자 정의 할 수 있습니다 만있다.

CPU / FPU 내장 명령을 사용하지 않고 정수 전용 명령을 통해이 숫자에 대한 모든 작업을 항상 시뮬레이션해야하기 때문에 속도가 느려져 수학 연산 당 훨씬 더 많은 명령이 발생합니다.

성능 저하를 줄이려면 QNumbers (Jonathan Dickinson의 답변 참조- 부동 소수점 수학이 C #에서 일관됩니까? 가능합니까? ) 및 / 또는 캐싱 (예 : 삼각 계산 등)과 같은 몇 가지 전략 이 있습니다 .


1
참고 BigInteger닷넷 4.0에서만 사용할 수 있습니다.
svick

내 생각 엔 BigInteger성능 저하가 Decimal의 성능 저하보다 훨씬 뛰어납니다.
코드 InChaos

여기에 대한 답변에 몇 번 (@Jonathan DecimalDickinson- 'dog slow') 또는 BigInteger(@CodeInChaos 코멘트 위) 를 사용했을 때의 성능 히트에 대한 참조가 있습니다. / 솔루션이 솔루션을 제공하는 데 실제로 실패하는 이유.
Barry Kaye

@Yahia-편집 주셔서 감사합니다-재미있는 독서, 그러나 당신은 또한 우리가 10 % 느리게 또는 10 배 느리게 말하고 있는지 'float'를 사용하지 않을 때의 성능 적중에 대해 추측을 할 수 있습니까? 암시 적 순서에 대한 느낌을 얻고 싶습니다.
Barry Kaye

"10 %"보다 1 : 5의 영역에서 더 유사하다
Yahia

2

글쎄, 이 작업을 수행하는 방법대한 나의 첫 번째 시도 는 다음과 같습니다.

  1. 중요한 부동 소수점 연산에 사용할 간단한 개체가있는 ATL.dll 프로젝트를 만듭니다. 부동 소수점을 수행하기 위해 xx87 이외의 하드웨어를 사용하지 않도록 설정하는 플래그로 컴파일해야합니다.
  2. 부동 소수점 연산을 호출하고 결과를 반환하는 함수를 만듭니다. 간단하게 시작한 다음 효과가있는 경우 나중에 필요한 경우 나중에 성능 요구를 충족시키기 위해 복잡성을 늘릴 수 있습니다.
  3. control_fp 호출을 실제 수학 주위에 두어 모든 머신에서 동일한 방식으로 수행되도록하십시오.
  4. 새 라이브러리를 참조하고 예상대로 작동하는지 테스트하십시오.

(32 비트 .dll로 컴파일 한 다음 x86 또는 AnyCpu (또는 64 비트 시스템에서 x86 만 타겟팅 할 수 있습니다. 아래 주석 참조)와 함께 사용할 수 있다고 생각합니다.)

그런 다음 작동한다고 가정하면 Mono를 사용하고 싶을 때 비슷한 방식으로 다른 x86 플랫폼에서 라이브러리를 복제 할 수 있다고 생각합니다 (물론 COM은 아니지만 와인을 사용합니까?) 우리는 거기에 간다 ...).

작동한다고 가정하면 성능 문제를 해결하기 위해 한 번에 여러 작업을 수행 할 수있는 사용자 정의 기능을 설정할 수 있어야하며 플랫폼에서 최소한의 결과로 일관된 결과를 얻을 수있는 부동 소수점 연산이 있습니다. C ++로 작성된 코드의 나머지 부분을 C #으로 남겨 둡니다.


"32 비트 .dll로 컴파일 한 다음 ... AnyCpu 사용"32 비트 시스템에서 실행할 때만 작동한다고 생각합니다. 64 비트 시스템에서는 프로그램 타겟팅 만 x8632 비트 dll을로드 할 수 있습니다.
코드 InChaos

2

나는 계산 개발자가 어려운 문제에 대해 많은 경험을 가지고 있지만 게임 개발자는 아닙니다 ... 그래서 최선을 다하겠습니다.

내가 채택 할 전략은 본질적으로 다음과 같습니다.

  • 더 느리게 (필요한 경우 더 빠른 방법이 있다면 훌륭합니다!), 재현 가능한 결과를 얻을 수있는 예측 가능한 방법을 사용하십시오
  • 다른 모든 것에는 두 배를 사용하십시오 (예 : 렌더링)

가장 짧은 것은 균형을 찾아야한다는 것입니다. 30ms 렌더링 (~ 33fps)을 소비하고 충돌 감지를 수행하는 데 1ms 만 소요되는 경우 (또는 매우 민감한 다른 작업을 삽입하는 경우) 중요한 산술을 수행하는 데 걸리는 시간이 3 배인 경우에도 프레임 속도에 미치는 영향은 33.3fps에서 30.3fps로 떨어집니다.

나는 모든 것을 프로파일 링하고 눈에 띄게 비싼 계산을 수행하는 데 걸리는 시간을 계산 한 다음이 문제를 해결하는 하나 이상의 방법으로 측정을 반복하고 그 영향을 확인하십시오.


1

다른 답변의 링크를 확인하면 부동 소수점이 "정확하게"구현되었는지 또는 주어진 계산에 대해 항상 일정한 정밀도를 받을지 여부를 보장 할 수는 없지만 최선의 노력을 다할 수 있습니다. (1) 모든 계산을 공통 최소값으로 절단 (예를 들어, 다른 구현으로 인해 32 ~ 80 비트의 정밀도를 제공하고 모든 작업을 항상 30 또는 31 비트로 절단하는 경우), (2) 시작할 때 몇 가지 테스트 사례 테이블이 있습니다. (더하기, 빼기, 곱하기, 나누기, sqrt, 코사인 등의 경계선 사례) 및 구현이 테이블과 일치하는 값을 계산하는 경우 조정을 방해하지 않습니다.


모든 작업을 항상 30 또는 31 비트로 자르십시오 . 이것은 floatx86 시스템 에서 데이터 유형이하는 것과 정확히 같지만 32 비트 만 사용하여 모든 계산을 수행하는 시스템과는 약간 다른 결과를 초래할 수 있으며 이러한 작은 변경 사항은 시간이 지남에 따라 전파됩니다. 따라서 질문입니다.
BlueRaja-대니 Pflughoeft

"정확도의 N 비트"가 계산에 많은 비트가 정확하고 기계 A가 32 비트에 정확하고 기계 B가 48 비트에 정확하면 두 기계에 의한 계산의 첫 32 비트는 동일해야합니다. 모든 작업 후에 두 시스템을 정확하게 동기화 한 후 32 비트 이하로 잘리지 않습니까? 그렇지 않은 경우 예는 무엇입니까?
증인 보호 ID 44583292

-3

매우 어렵고 기술적 인 것들에 대한 질문 O_o. 그러나 나는 아이디어가있을 수 있습니다.

플로팅 작업 후 CPU가 약간 조정된다는 것을 알고 있습니다. 그리고 CPU는 다른 반올림 작업을 수행하는 여러 가지 명령을 제공합니다.

따라서 표현식의 경우 컴파일러는 결과로 연결되는 명령어 세트를 선택합니다. 그러나 다른 명령어 워크 플로는 동일한 식을 계산하더라도 다른 결과를 제공 할 수 있습니다.

반올림 조정으로 인한 '실수'는 각 추가 지시에 따라 증가합니다.

예를 들어 어셈블리 레벨에서 a * b * c는 a * c * b와 동일하지 않다고 말할 수 있습니다.

나는 완전히 확신하지 못합니다 .CPU 아키텍처를 알고있는 사람에게 저보다 훨씬 더 많은 것을 요구해야합니다 : p

그러나 귀하의 질문에 대답하십시오 : C 또는 C ++에서는 컴파일러가 생성하는 기계 코드를 약간 제어 할 수 있기 때문에 문제를 해결할 수 있지만 .NET에는 아무것도 없습니다. 따라서 기계 코드가 다를 수있는 한 정확한 결과를 확신 할 수는 없습니다.

변동이 매우 작게 보이기 때문에 이것이 문제가 될 수있는 방법이 궁금합니다. 그러나 정확한 연산이 필요한 경우 부동 레지스터의 크기를 늘리는 것입니다. 가능하면 배정도 또는 Long double을 사용하십시오 (CLI를 사용하여 가능한지 확실하지 않음).

나는 충분히 명확했으면 좋겠다. 영어로 완벽하지는 않다. (... 모두 : s)


9
P2P 슈팅 게임을 상상해보십시오. 당신은 한 남자를 쏴 죽이고 그를 죽 였지만 아주 가까워서 거의 놓쳤습니다. 다른 사람의 PC에서는 약간 다른 계산을 사용하고 놓친 계산합니다. 지금 문제가 보입니까? 이 경우 레지스터 크기를 늘리면 도움이되지 않습니다 (적어도 완전히는 아님). 각 컴퓨터에서 똑같은 계산을 사용하면됩니다.
svick

5
이 시나리오에서는 일반적으로 결과가 실제 결과와 얼마나 가까운 지에 대해서는 신경 쓰지 않지만 (중요한 경우) 모든 사용자에 대해 정확히 동일 하다는 것이 중요 합니다.
코드 InChaos

1
당신은 그렇습니다, 나는 이런 종류의 시나리오에 대해서는 생각하지 않았습니다. 그러나 나는 이것에 대해 @CodeInChaos에 동의합니다. 중요한 결정을 두 번하는 것이 현명하다는 것을 알지 못했습니다. 이것은 소프트웨어 아키텍처 문제입니다. 범인의 exemple 응용 프로그램 중 하나의 프로그램이 계산을 수행하고 다른 프로그램에 결과를 보내야합니다. 이런 식으로 오류가 발생하지 않습니다. 당신은 명중이 있든 없든, 오직 한 사람 만이 결정을 내립니다. @driushkin와 같은 말
AxFab

2
@Aesgar : 그렇습니다. 대부분의 범인이 일하는 방식입니다. "권한"을 서버라고하며 전체 아키텍처를 "클라이언트 / 서버"아키텍처라고합니다. 그러나 또 다른 종류의 아키텍처 인 피어 투 피어가 있습니다. P2P에는 서버가 없습니다. 오히려 모든 클라이언트는 어떤 일이 발생하기 전에 서로의 모든 작업을 확인해야합니다. 이로 인해 지연이 증가하여 사수에게는 허용되지 않지만 네트워크 트래픽이 크게 감소하여 작은 지연 (약 250ms)은 허용되지만 전체 게임 상태를 동기화 할 수 없는 게임에는 적합합니다. 즉, C & C 및 Starcraft와 같은 RTS 게임은 P2P를 사용합니다.
BlueRaja-대니 Pflughoeft

5
p2p 게임에서는 신뢰할 수있는 컴퓨터가 없습니다. 한 스테이션에서 총알이 맞았는지 여부를 결정할 수 있으면 클라이언트가 부정 행위를 할 가능성이 있습니다. 또한 링크는 때때로 결과로 나타나는 데이터의 양도 처리 할 수 ​​없습니다. 게임은 결과가 아닌 명령을 보내서 작동합니다. 나는 RTS 게임을하고 여러 번 정크가 날아 다니는 것을 보았는데 정상적인 가정용 업 링크를 통해 보낼 수있는 방법은 없습니다.
Loren Pechtel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.