Double的乘法不如float的

时间:2015-08-19 19:34:05

标签: c++ floating-point double

假设我们有方程y = k1 * x + b1 = k2 * x + b2。我们用浮点数计算x。我知道这是一个糟糕的选择,但我想了解我得到的结果的原因。还让我们使用这个x来计算y然后做同样的事情,但是使用double(x)。请考虑以下代码:

std::cout.precision(20);

float k1, b1, k2, b2;
std::cin >> k1 >> b1 >> k2 >> b2;

float x_f = (b2 - b1) / (k1 - k2);
double x_d = x_f;
printFloat(x_f); // my function which prints number and it's binary representation
printDouble(x_d);
float y_f = x_f * k1 + b1;
double y_d = x_d * k1 + b1;
printFloat(y_f);
printDouble(y_d);

当k1 = -4653时,b1 = 9968,k2 = 520,b2 = -1370令人惊讶地得到以下结果:

x_f = 2.19176483154296875 01000000000011000100010111100000
x_d = 2.19176483154296875 0100000000000001100010001011110000000000000000000000000000000000
y_f = -230.2822265625 11000011011001100100100001000000
y_d = -230.28176116943359375 1100000001101100110010010000010000110000000000000000000000000000

而更准确的答案(使用Python Decimal计算)是:

x = 2.191764933307558476705973323023390682389
y = -230.28223468006959211289387202783684516

浮球的答案比双人的更接近!为什么会这样?我用gdb调试(在64位Ubuntu 14.04 g ++ 4.8.4上编译)并查看了指令,它们都没问题,所以这是由于乘法。

1 个答案:

答案 0 :(得分:3)

巧合的是,舍入取消并最终与float比与double更接近。差异的来源是x_d * k1被提升为double,而x_f * k1被评估为float

为了提供一个更简单的示例,说明这种舍入如何导致低精度类型产生更准确的答案,请考虑两个名为sf2sf3的新数字类型,每个类型都存储基数为10的数字,分别为2位和3位有效数字。然后考虑以下计算:

// Calculate (5 / 4) * 8. Expected result: 10
sf2 x_2 = 5.0 / 4.0; // 1.3
sf2 y_2 = x_2 * 8.0; // 10
sf3 x_3 = x_2; // 1.30
sf3 y_3 = x_3 * 8.0; // 10.4

请注意,使用上述类型,即使sf2类型中的所有sf3值都可以表示,sf2计算也更准确。这是因为在将1.25四舍五入到1.3时,计算x_210.410的总结正好取消了。但是当使用sf3类型完成第二次计算时,初始向上舍入将保持不变,但向下舍入不再发生。

这是处理浮点类型时会遇到的许多陷阱的一个例子。