부동 소수점 산술을위한 IEEE 754-2008 표준 및 ISO / IEC 10967 LIA (Language Independent Arithmetic) 표준, 1 부는 이것이 왜 그런지에 대한 답변입니다.
IEEE 754 § 6.3 부호 비트
입력 또는 결과가 NaN 인 경우이 표준은 NaN의 부호를 해석하지 않습니다. 그러나 비트 문자열 (copy, negate, abs, copySign)에 대한 작업은 NaN 피연산자의 부호 비트에 따라 NaN 결과의 부호 비트를 지정합니다. 논리 술어 totalOrder도 NaN 피연산자의 부호 비트의 영향을받습니다. 다른 모든 작업의 경우이 표준은 입력 NaN이 하나만 있거나 유효하지 않은 작업으로 NaN이 생성 된 경우에도 NaN 결과의 부호 비트를 지정하지 않습니다.
입력 값이나 결과가 NaN이 아닌 경우 곱 또는 부호의 부호는 피연산자 부호의 배타적 OR입니다. 합의 부호 또는 합 x + (-y)로 간주되는 차이 x-y는 최대 부수 부호와 다릅니다. 변환 결과의 부호, 양자화 연산, roundTo-Integral 연산 및 roundToIntegralExact (5.3.1 참조)는 첫 번째 또는 유일한 피연산자의 부호입니다. 이 규칙은 피연산자 또는 결과가 0 또는 무한 인 경우에도 적용됩니다.
반대 부호를 가진 두 피연산자의 합 (또는 같은 부호를 가진 두 피연산자의 차이)이 정확히 0 인 경우 roundTowardNegative를 제외한 모든 반올림 방향 속성에서 해당 합 (또는 차이)의 부호는 +0이어야합니다. 이 속성 하에서, 정확한 제로섬 (또는 차이)의 부호는 -0이어야한다. 그러나 x가 0 인 경우에도 x + x = x − (−x)는 x와 동일한 부호를 유지합니다.
덧셈의 경우
기본 반올림 모드 (라운드에서 가장 가까운, 타이 에서 에븐까지 )에서 다음과 같은 경우를 제외 하고 x+0.0
생성합니다 . 이 추가로 생성되는 3 가지 규칙 .x
x
-0.0
+0.0
이후이 +0.0
아닌 비트 본래 동일 -0.0
하고, 그-0.0
입력으로 발생할 수있는 정상적인 값은 컴파일러에 부정적 제로 변환 될 코드에 배치해야만한다 +0.0
.
요약 : 기본 아래에서, 반올림 모드 x+0.0
경우,x
- 하지
-0.0
후,x
자체는 허용 가능한 출력 값입니다.
- 이면
-0.0
출력 값 은 +0.0
비트 단위와 동일하지 않아야합니다 -0.0
.
곱셈의 경우
기본 반올림 모드 에서는 이러한 문제가 발생하지 않습니다 x*1.0
. 만약x
:
빼기의 경우
기본 반올림 모드 에서 뺄셈 x-0.0
도와 동일하므로 뺄셈 도 작동하지 않습니다 x + (-0.0)
. 만약 x
에
- 는
NaN
§6.3p1 및 §6.2.3이 덧셈 및 곱셈과 거의 같은 방식으로 적용됩니다.
- 이면
+/- infinity
결과는 +/- infinity
같은 부호입니다.
x-0.0 == x
항상 (하) 정수 입니다.
- 인
-0.0
"다음 §6.3p2 의해 우리가, ...], 또는 차 X의 합계의 부호 - 간주 Y 합계 X + (-y) 상기 가수 '기호 많아야 하나 다르다; ". 이 힘을 우리는 할당 -0.0
의 결과로 (-0.0) + (-0.0)
인해 -0.0
에서 로그인 다르다 없음 가산 수의, 동안 +0.0
의 기호에 다릅니다 이 이 조항의 위반에 가수의.
- 이고
+0.0
, 이것은 가산 경우에 감소 (+0.0) + (-0.0)
위에서 고려 첨가 케이스 §6.3p3 의해 수득 지배된다 +0.0
.
모든 경우에 입력 값이 출력으로 합법적이기 때문에 x-0.0
no-op 및 x == x-0.0
타우 톨로지를 고려할 수 있습니다.
가치 변화 최적화
IEEE 754-2008 표준에는 다음과 같은 흥미로운 인용문이 있습니다.
IEEE 754 § 10.4 리터럴 의미 및 가치 변경 최적화
[...]
다음과 같은 값 변경 변환은 소스 코드의 문자 적 의미를 유지합니다.
- x가 0이 아니고 신호 NaN이 아니고 결과가 x와 동일한 지수를 갖는 경우 항등 속성 0 + x를 적용합니다.
- x가 신호 NaN이 아니고 결과가 x와 동일한 지수를 갖는 경우 항등 성 1 × x를 적용합니다.
- 조용한 NaN의 페이로드 또는 부호 비트 변경
- [...]
모든 NaN이 모든 무한이 같은 지수, 그리고 올바르게 둥근 결과를 공유하기 때문에 x+0.0
와 x*1.0
유한에 대해 x
정확히 같은 크기 등이있다x
, 그들의 지수는 동일합니다.
sNaNs
시그널링 NaN은 부동 소수점 트랩 값입니다. 부동 소수점 피연산자로 사용하면 SIGFPE (잘못된 연산 예외)가 발생하는 특수 NaN 값입니다. 예외를 트리거하는 루프가 최적화 된 경우 소프트웨어는 더 이상 동일하게 동작하지 않습니다.
그러나 user2357112 가 주석에서 지적한 바와 같이 C11 표준은 NaN 신호의 동작을 정의되지 않은 채로 둡니다 (sNaN
) 므로 컴파일러는 발생하지 않는다고 가정 할 수 있으므로 발생하는 예외도 발생하지 않습니다. C ++ 11 표준은 NaN 신호에 대한 동작을 설명하지 않으므로 정의되지 않은 상태로 둡니다.
반올림 모드
대체 라운딩 모드에서는 허용되는 최적화가 변경 될 수 있습니다. 예를 들어, Round-to-Negative-Infinity 모드에서는 최적화 x+0.0 -> x
가 허용되지만x-0.0 -> x
금지됩니다.
GCC가 기본 반올림 모드와 동작을 가정하지 않도록 실험 플래그 -frounding-math
를 GCC로 전달할 수 있습니다.
결론
에 있더라도 Clang 및 GCC-O3
는 IEEE-754를 준수합니다. 이는 IEEE-754 표준의 위 규칙을 준수해야 함을 의미합니다. x+0.0
인 비트와 동일하지 에 x
모두 x
그 규칙 하에서하지만 x*1.0
그렇게되도록 선택 될 수있다 : 때, 즉
x
NaN 인 경우 페이로드를 변경하지 말 것을 권장합니다 .
- NaN 결과의 부호 비트는 다음과 같이 변경하지 마십시오.
* 1.0
.
- NaN
x
이 아닌 경우 몫 / 제품 중에 부호 비트를 XOR하는 순서를 따르십시오 .
IEEE-754 안전하지 않은 최적화 (x+0.0) -> x
를 사용하려면 플래그 -ffast-math
를 Clang 또는 GCC에 전달해야합니다.