双精度的乘法不如浮点数的乘法精确
Double's multiplication is less precise than float's one
假设有方程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
并且float的答案比double的答案更接近!为什么会发生这种情况?我用gdb(在64位Ubuntu 14.04 g++ 4.8.4上编译)进行了调试,并查看了说明,它们都没问题,所以这是由于乘法。
这是一个巧合,四舍五入抵消,最终更接近float
而不是double
。差异的根源在于x_d * k1
被提升为double
,而x_f * k1
被评估为float
。
为了提供一个更简单的例子,说明这种舍入如何使低精度类型产生更准确的答案,考虑两个新的数字类型sf2
和sf3
,它们分别存储以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
的计算更准确。这是因为计算x_2
时将1.25
四舍五入到10
时将CC_12四舍五入到1.3
。但是,当使用sf3
类型完成第二次计算时,保留初始的四舍五入,但不再进行四舍五入。
这是您在处理浮点类型时会遇到的许多陷阱的一个例子。
相关文章:
- 在C++中序列化浮点数/双精度,编译为 WebAssembly
- 如何提高计算浮点数的精度?
- 我们如何清楚地知道 C/C++ 中的双精度或浮点数的精度?
- 这是为浮点数/双精度函数泛型的正确方法吗?
- 关于在C/C++中比较整数和浮点/双精度
- 如何在没有浮点数/双精度数的情况下生成均匀和高斯分布的伪随机数
- 具有 IEEE 754 浮点双精度数据类型的安全往返整数值
- 将浮点浮点/双精度的其余部分转换为整数
- 为什么在C和C++中没有浮点/双精度的除法余数运算
- 使用浮点/双精度作为循环变量
- 字符数据浮点数/双精度数
- 宏或函数,用于根据给定的符号、尾数和指数构造浮点(双精度)
- C++将SATOSHI(uint64_t)转换为不带浮点/双精度的BTC(string)
- C++将字符串转换为浮点/双精度,而不会丢失数据
- 将输入字符串转换为浮点/双精度C++
- 在运行时定义双精度或浮点数的精度/大小
- 整数和分数为浮点数/双精度
- 在c++中控制浮点数的精度
- c++中浮点数/双精度数的比较
- 以 32 个十进制数字分析浮点数/双精度