gpt4 book ai didi

c++ - 分配两个 double 保证产生相同的位集模式吗?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:09:26 29 4
gpt4 key购买 nike

这里有几篇关于 float 及其性质的文章。很明显comparing floats and doubles必须始终谨慎地进行。 Asking for equality也有讨论过,建议明确是远离它。

但是如果有直接赋值怎么办:

double a = 5.4;
double b = a;

假设 a 是任何非 NaN值 - a == b 会是 false 吗?

答案显然是否定的,但我找不到在 C++ 环境中定义此行为的任何标准。 IEEE-754 声明两个具有相等(非 NaN)位集模式的 float 相等。现在是否意味着我可以继续以这种方式比较我的 double 而不必担心可维护性?我是否需要担心其他编译器/操作系统及其对这些行的实现?或者可能是一个编译器优化了一些位并破坏了它们的相等性?

我写了一个小程序,可以永远生成和比较非 NaN 随机 double 值 - 直到找到 a == b 产生 false 的情况。我可以在未来随时随地编译/运行这段代码而不必期待停止吗? (忽略字节序并假设符号、指数和尾数位大小/位置保持不变)。

#include <iostream>
#include <random>

struct double_content {
std::uint64_t mantissa : 52;
std::uint64_t exponent : 11;
std::uint64_t sign : 1;
};
static_assert(sizeof(double) == sizeof(double_content), "must be equal");


void set_double(double& n, std::uint64_t sign, std::uint64_t exponent, std::uint64_t mantissa) {
double_content convert;
memcpy(&convert, &n, sizeof(double));
convert.sign = sign;
convert.exponent = exponent;
convert.mantissa = mantissa;
memcpy(&n, &convert, sizeof(double_content));
}

void print_double(double& n) {
double_content convert;
memcpy(&convert, &n, sizeof(double));
std::cout << "sign: " << convert.sign << ", exponent: " << convert.exponent << ", mantissa: " << convert.mantissa << " --- " << n << '\n';
}

int main() {
std::random_device rd;
std::mt19937_64 engine(rd());
std::uniform_int_distribution<std::uint64_t> mantissa_distribution(0ull, (1ull << 52) - 1);
std::uniform_int_distribution<std::uint64_t> exponent_distribution(0ull, (1ull << 11) - 1);
std::uniform_int_distribution<std::uint64_t> sign_distribution(0ull, 1ull);

double a = 0.0;
double b = 0.0;

bool found = false;

while (!found){
auto sign = sign_distribution(engine);
auto exponent = exponent_distribution(engine);
auto mantissa = mantissa_distribution(engine);

//re-assign exponent for NaN cases
if (mantissa) {
while (exponent == (1ull << 11) - 1) {
exponent = exponent_distribution(engine);
}
}
//force -0.0 to be 0.0
if (mantissa == 0u && exponent == 0u) {
sign = 0u;
}


set_double(a, sign, exponent, mantissa);
b = a;

//here could be more (unmodifying) code to delay the next comparison

if (b != a) { //not equal!
print_double(a);
print_double(b);
found = true;
}
}
}

使用 Visual Studio Community 2017 版本 15.9.5

最佳答案

C++标准在[basic.types]#3中明确规定:

For any trivially copyable type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a potentially-overlapping subobject, if the underlying bytes ([intro.memory]) making up obj1 are copied into obj2, obj2 shall subsequently hold the same value as obj1.

它给出了这个例子:

T* t1p;
T* t2p;
// provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
// at this point, every subobject of trivially copyable type in *t1p contains
// the same value as the corresponding subobject in *t2p

剩下的问题是什么是。我们在 [basic.fundamental]#12 中找到(强调我的):

There are three floating-point types: float, double, and long double. The type double provides at least as much precision as float, and the type long double provides at least as much precision as double. The set of values of the type float is a subset of the set of values of the type double; the set of values of the type double is a subset of the set of values of the type long double. The value representation of floating-point types is implementation-defined.

由于 C++ 标准对如何表示浮点值没有进一步的要求,这就是标准的保证,因为赋值只需要保留([expr.ass]#2 ):

In simple assignment (=), the object referred to by the left operand is modified by replacing its value with the result of the right operand.

正如您正确观察到的那样,IEEE-754 要求非 NaN、非零 float 当且仅当它们具有相同的位模式时比较相等。因此,如果您的编译器使用符合 IEEE-754 标准的 float ,您应该会发现非 NaN、非零 float 的赋值会保留位模式。


事实上,你的代码

double a = 5.4;
double b = a;

绝不允许 (a == b) 返回 false。但是,一旦用更复杂的表达式替换 5.4,这种细微差别就会消失。这不是文章的确切主题,而是https://randomascii.wordpress.com/2013/07/16/floating-point-determinism/提到了几种看起来无辜的代码可以产生不同结果的可能方式(这打破了“与位模式相同”的断言)。特别是,您可能会将 80 位中间结果与 64 位舍入结果进行比较,这可能会产生不等式。

关于c++ - 分配两个 double 保证产生相同的位集模式吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55379715/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com