Consider the following code in C++, compiled with Visual Studio 2022:
#include <iostream>
#include <intrin.h>
int main() {
std::cout << _cvt_dtoll_sent(1e31) << "\n";
std::cout << _cvt_dtoll_sat(1e31) << "\n";
std::cout << _cvt_dtoll_fast(1e31) << "\n";
std::cout << (long long)1e31 << "\n";
}
In x86 it prints:
-9223372036854775808
9223372036854775807
4016683251292700672
-4571153621781053440
In x64 it prints:
-9223372036854775808
9223372036854775807
-9223372036854775808
-4571153621781053440
The program uses four different ways to convert double
to long long
. As 1e31
does not fit into long long
(signed 64-bit integer), the behavior is undefined under C++ standard. However, VS2022 has a special option that defaults to /fpcvt:BC
, quoting:
The /fpcvt:BC option also makes conversion to signed types return the minimum possible value when the source is invalid
So I'd expect (long long)1e31
to return a sentinel value of -9223372036854775808
, just like _cvt_dtoll_sent
. However, not only it does not return the sentinel, it does not coincide with either "saturated" or "fast" version of the conversion. Why is that?