우선, 부동 소수점 값은 동작에서 "임의"가 아닙니다. 정확한 비교는 많은 실제 사용에서 의미가 있습니다. 그러나 부동 소수점을 사용하려면 작동 방식을 알고 있어야합니다. 부동 소수점이 실수처럼 작동한다고 가정하면 실수로 코드가 빠르게 중단됩니다. 부동 소수점 결과에 관련하여 큰 임의의 퍼즈가 있다고 가정하면 (여기에서 대부분의 대답이 제안하는 것처럼) 처음에는 작동하는 것처럼 보이지만 큰 크기의 오류가 발생하고 모서리가 부러진 코드가 생성됩니다.
우선, 부동 소수점으로 프로그래밍하려면 다음을 읽어야합니다.
부동 소수점 산술에 대해 모든 컴퓨터 과학자가 알아야 할 사항
네, 전부 읽어보세요. 그것이 너무 많은 부담이라면, 읽을 시간이 될 때까지 계산에 정수 / 고정 소수점을 사용해야합니다. :-)
이제는 정확한 부동 소수점 비교의 가장 큰 문제는 다음과 같습니다.
값이 많이 당신이 소스, 쓰기,로 읽을 수 있다는 사실 scanf
하거나 strtod
, 존재하지 않는 부동 소수점 값으로하고 자동으로 가장 가까운 근사치로 변환됩니다. 이것이 demon9733의 대답이었습니다.
실제 결과를 나타내기에 충분한 정밀도가 없기 때문에 많은 결과가 반올림됩니다. 이것을 볼 수있는 쉬운 예는 추가 x = 0x1fffffe
하고 y = 1
수레입니다. 여기 x
에서 가수 (ok)에서 24 비트의 정밀도를 y
가지며 1 비트 만 있습니다. 그러나 비트를 추가하면 해당 비트가 겹치는 위치에 있지 않으므로 결과에는 25 비트의 정밀도가 필요합니다. 대신 반올림됩니다 ( 0x2000000
기본 반올림 모드에서).
정확한 값을 얻기 위해 무한히 많은 장소가 필요하기 때문에 많은 결과가 반올림된다는 사실. 여기에는 1/3과 같은 합리적인 결과가 포함됩니다 (무한한 많은 장소를 차지하는 10 진수에 익숙 함)뿐만 아니라 1/10 (5는 2의 거듭 제곱이 아니기 때문에 2 진수로 무한히 많은 장소를 차지합니다), 완벽한 제곱이 아닌 것의 제곱근과 같은 비이성적 인 결과뿐만 아니라.
이중 반올림. 일부 시스템 (특히 x86)에서 부동 소수점 표현식은 공칭 유형보다 높은 정밀도로 평가됩니다. 즉, 위의 반올림 유형 중 하나가 발생하면 두 가지 반올림 단계가 시작됩니다. 먼저 결과를 고정밀 유형으로 반올림 한 다음 최종 유형으로 반올림합니다. 예를 들어, 1.49를 정수 (1)로 반올림하면 10 진수로 발생하는 것과, 소수점 이하 1 자리 (1.5)로 반올림 한 후 결과를 정수 (2)로 반올림하면 어떻게되는지를 고려하십시오. 이는 컴파일러의 동작 (특히 GCC와 같은 버그가있는 비준수 컴파일러의 경우)을 예측할 수 없기 때문에 실제로 부동 소수점에서 처리 할 수있는 가장 단순한 영역 중 하나입니다.
초월 함수 ( trig
, exp
, log
등)의 결과 정확하게 원형을 갖도록 지정되지; 결과는 마지막 정밀도 (보통 1ulp ) 에서 한 단위 내에서 정확하도록 지정되었습니다 .
부동 소수점 코드를 작성할 때 결과가 정확하지 않은 숫자로 무엇을하고 있는지를 염두에두고 그에 따라 비교해야합니다. 종종 "엡실론"과 비교하는 것이 합리적이지만, 엡실론은 절대 상수가 아니라 비교하는 숫자 의 크기를 기반으로해야합니다 . (절대 상수 엡실론이 작동하는 경우 부동 소수점이 아닌 고정 소수점이 작업에 적합한 도구임을 강력하게 나타냅니다!)
편집 : 특히 크기 기준 엡실론 검사는 다음과 같아야합니다.
if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y))
어디 FLT_EPSILON
에서 일정 float.h
(로 교체 DBL_EPSILON
를위한 double
s 또는 LDBL_EPSILON
위해 long double
들) 및 K
당신이 당신의 계산의 누적 오류가 확실히에 의해 제한되도록 선택 상수 K
마지막 장소의 단위는 (확실하지 않은 경우에는 오류가 발생했습니다 바운드 계산, K
계산이 말한 것보다 몇 배 더 큼).
마지막으로,이 기능을 사용하면 FLT_EPSILON
비정규에는 적합하지 않기 때문에 0 근처에서 특별한주의가 필요할 수 있습니다 . 빠른 수정은 다음과 같습니다.
if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y) || fabs(x-y) < FLT_MIN)
DBL_MIN
복식을 사용하는 경우에도 마찬가지 입니다.
fabs(x+y)
(x
와y
) 다른 부호를 가질 수 있다면 문제가됩니다 . 여전히화물 컬트 비교의 조류에 대한 좋은 대답.