浮点数到整数的转换四舍五入而不是截断
Floating-point-to-integer conversion rounding up instead of truncating
我惊讶地发现浮点数到整数的转换是四舍五入而不是截断小数部分。下面是一些示例代码,使用 Clang 编译,重现了该行为:
double a = 1.12; // 1.1200000000000001 * 2^0
double b = 1024LL * 1024 * 1024 * 1024 * 1024; // 1 * 2^50
double c = a * b; // 1.1200000000000001 * 2^50
long long d = c; // 1261007895663739
使用精确数学,浮点值表示
1.1200000000000001 * 2^50 = 1261007895663738.9925899906842624
由于截断,我原以为生成的整数是 1261007895663738
,但实际上是 1261007895663739
。为什么?
假设 IEEE 754 双精度,1.12 正好是
1.12000000000000010658141036401502788066864013671875
写成二进制,它的有效位数正好是:
1.0001111010111000010100011110101110000101000111101100
请注意最后两个零是有意为之的,因为它是双精度得到的(小数分隔符前 1 位,加上 52 位小数位)。
因此,如果您移动 50 个位置,您将得到一个整数值
100011110101110000101000111101011100001010001111011.00
或十进制
1261007895663739
转换为long long时,没有发生truncation/rounding,转换是正确的。
Using exact math, the floating-point value represents ...
a
不完全是 1.12 因为 0.12 不是 dyadic.
// `a` not exactly 1.12
double a = 1.12; // 1.1200000000000001 * 2^0
附近的 double
个值:
1.11999999999999988... Next closest double
1.12 Code
1.12000000000000011... Closest double
1.12000000000000033...
相反,让我们更接近真实值。
#include <stdio.h>
#include <float.h>
int main() {
double a = 1.12; // 1.1200000000000001 * 2^0
double b = 1024LL * 1024 * 1024 * 1024 * 1024; // 1 * 2^50
int prec = DBL_DECIMAL_DIG;
printf("a %.*e\n", prec, a);
printf("b %.*e\n", prec, b);
double c = a * b;
double whole;
printf("c %.*e (r:%g)\n", prec, c, modf(c, &whole));
long long d = (long long) c;
printf("d %lld\n", d);
}
输出
a 1.12000000000000011e+00
b 1.12589990684262400e+15
c 1.26100789566373900e+15 (r:0)
d 1261007895663739
我惊讶地发现浮点数到整数的转换是四舍五入而不是截断小数部分。下面是一些示例代码,使用 Clang 编译,重现了该行为:
double a = 1.12; // 1.1200000000000001 * 2^0
double b = 1024LL * 1024 * 1024 * 1024 * 1024; // 1 * 2^50
double c = a * b; // 1.1200000000000001 * 2^50
long long d = c; // 1261007895663739
使用精确数学,浮点值表示
1.1200000000000001 * 2^50 = 1261007895663738.9925899906842624
由于截断,我原以为生成的整数是 1261007895663738
,但实际上是 1261007895663739
。为什么?
假设 IEEE 754 双精度,1.12 正好是
1.12000000000000010658141036401502788066864013671875
写成二进制,它的有效位数正好是:
1.0001111010111000010100011110101110000101000111101100
请注意最后两个零是有意为之的,因为它是双精度得到的(小数分隔符前 1 位,加上 52 位小数位)。
因此,如果您移动 50 个位置,您将得到一个整数值
100011110101110000101000111101011100001010001111011.00
或十进制
1261007895663739
转换为long long时,没有发生truncation/rounding,转换是正确的。
Using exact math, the floating-point value represents ...
a
不完全是 1.12 因为 0.12 不是 dyadic.
// `a` not exactly 1.12
double a = 1.12; // 1.1200000000000001 * 2^0
附近的 double
个值:
1.11999999999999988... Next closest double
1.12 Code
1.12000000000000011... Closest double
1.12000000000000033...
相反,让我们更接近真实值。
#include <stdio.h>
#include <float.h>
int main() {
double a = 1.12; // 1.1200000000000001 * 2^0
double b = 1024LL * 1024 * 1024 * 1024 * 1024; // 1 * 2^50
int prec = DBL_DECIMAL_DIG;
printf("a %.*e\n", prec, a);
printf("b %.*e\n", prec, b);
double c = a * b;
double whole;
printf("c %.*e (r:%g)\n", prec, c, modf(c, &whole));
long long d = (long long) c;
printf("d %lld\n", d);
}
输出
a 1.12000000000000011e+00
b 1.12589990684262400e+15
c 1.26100789566373900e+15 (r:0)
d 1261007895663739