天天看點

為什麼NaN - NaN == 0.0與英特爾C ++編譯器?

本文翻譯自:Why does NaN - NaN == 0.0 with the Intel C++ Compiler?

It is well-known that NaNs propagate in arithmetic, but I couldn't find any demonstrations, so I wrote a small test:

衆所周知,NaNs在算術中傳播,但我找不到任何示範,是以我寫了一個小測試:
#include <limits>
#include <cstdio>

int main(int argc, char* argv[]) {
    float qNaN = std::numeric_limits<float>::quiet_NaN();

    float neg = -qNaN;

    float sub1 = 6.0f - qNaN;
    float sub2 = qNaN - 6.0f;
    float sub3 = qNaN - qNaN;

    float add1 = 6.0f + qNaN;
    float add2 = qNaN + qNaN;

    float div1 = 6.0f / qNaN;
    float div2 = qNaN / 6.0f;
    float div3 = qNaN / qNaN;

    float mul1 = 6.0f * qNaN;
    float mul2 = qNaN * qNaN;

    printf(
        "neg: %f\nsub: %f %f %f\nadd: %f %f\ndiv: %f %f %f\nmul: %f %f\n",
        neg, sub1,sub2,sub3, add1,add2, div1,div2,div3, mul1,mul2
    );

    return 0;
}
           

The example ( running live here ) produces basically what I would expect (the negative is a little weird, but it kind of makes sense):

這個例子( 在這裡運作 )基本上産生了我所期望的(負面有點奇怪,但它有點意義):
neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan
           

MSVC 2015 produces something similar.

MSVC 2015産生類似的東西。

However, Intel C++ 15 produces:

但是,英特爾C ++ 15産生:
neg: -nan(ind)
sub: nan nan 0.000000
add: nan nan
div: nan nan nan
mul: nan nan
           

Specifically,

qNaN - qNaN == 0.0

.

具體來說,

qNaN - qNaN == 0.0

This... can't be right, right?

這......不可能是對的,對嗎?

What do the relevant standards (ISO C, ISO C++, IEEE 754) say about this, and why is there a difference in behavior between the compilers?

相關标準(ISO C,ISO C ++,IEEE 754)對此有何評論,為什麼編譯器之間的行為存在差異?

#1樓

參考:https://stackoom.com/question/2B5dV/為什麼NaN-NaN-與英特爾C-編譯器

#2樓

The default floating point handling in Intel C++ compiler is

/fp:fast

, which handles

NaN

's unsafely (which also results in

NaN == NaN

being

true

for example).

英特爾C ++編譯器中的預設浮點處理是

/fp:fast

,它不安全地處理

NaN

(例如,這也導緻

NaN == NaN

true

)。

Try specifying

/fp:strict

or

/fp:precise

and see if that helps.

嘗試指定

/fp:strict

/fp:precise

,看看是否有幫助。

#3樓

This .

這個 。

.

.

can't be right, right?

不能對,對吧?

My question: what do the relevant standards (ISO C, ISO C++, IEEE 754) say about this?

我的問題:相關标準(ISO C,ISO C ++,IEEE 754)對此有何看法?

Petr Abdulin already answered why the compiler gives a

0.0

answer.

Petr Abdulin已經回答了編譯器給出

0.0

答案的原因。

Here is what IEEE-754:2008 says:

以下是IEEE-754:2008所說的内容:
(6.2 Operations with NaNs) "[...] For an operation with quiet NaN inputs, other than maximum and minimum operations, if a floating-point result is to be delivered the result shall be a quiet NaN which should be one of the input NaNs." (6.2使用NaN的操作)“[...]對于具有安靜NaN輸入的操作,除了最大和最小操作之外,如果要傳遞浮點結果,結果應該是一個安靜的NaN,它應該是一個輸入NaN。“

So the only valid result for the subtraction of two quiet NaN operand is a quiet NaN;

是以減去兩個安靜的NaN操作數的唯一有效結果是一個安靜的NaN;

any other result is not valid.

任何其他結果無效。

The C Standard says:

C标準說:
(C11, F.9.2 Expression transformations p1) "[...] (C11,F.9.2表達式轉換p1)“[...] x − x → 0. 0 "The expressions x − x and 0. 0 are not equivalent if x is a NaN or infinite" x - x→0。0“如果x是NaN或無窮大,則表達式x - x和0 0不相等”

(where here NaN denotes a quiet NaN as per F.2.1p1 "This specification does not define the behavior of signaling NaNs. It generally uses the term NaN to denote quiet NaNs")

(其中NaN表示根據F.2.1p1的安靜NaN“此規範沒有定義信号NaN的行為。它通常使用術語NaN來表示安靜的NaN”)

#4樓

Since I see an answer impugning the standards compliance of Intel's compiler, and no one else has mentioned this, I will point out that both GCC and Clang have a mode in which they do something quite similar.

由于我看到一個答案違反了英特爾編譯器的标準符合性,并且沒有其他人提到這一點,我将指出GCC和Clang都有一種模式,他們做了類似的事情。

Their default behavior is IEEE-compliant —

它們的預設行為符合IEEE标準 -
$ g++ -O2 test.cc && ./a.out 
neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan

$ clang++ -O2 test.cc && ./a.out 
neg: -nan
sub: -nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan
           

— but if you ask for speed at the expense of correctness, you get what you ask for —

- 但如果你以犧牲正确性為代價來要求速度,那麼你得到你所要求的 -
$ g++ -O2 -ffast-math test.cc && ./a.out 
neg: -nan
sub: nan nan 0.000000
add: nan nan
div: nan nan 1.000000
mul: nan nan

$ clang++ -O2 -ffast-math test.cc && ./a.out 
neg: -nan
sub: -nan nan 0.000000
add: nan nan
div: nan nan nan
mul: nan nan
           

I think it is entirely fair to criticize ICC's choice of default , but I would not read the entire Unix wars back into that decision.

我認為批評ICC的預設選擇是完全公平的,但我不會将整個Unix戰争重新納入該決定。