c++ - g++ 和双精度
问题描述
谁能向我解释为什么执行以下代码会返回 (1./3.)*3。等于1。?我假设四舍五入会阻止这种平等,但显然它不是那样工作的。有什么解释吗?
#include <iostream>
int main()
{
double x = 1./3.;
double y = 3.*x;
std::cout.precision(30);
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
if (y == 1.)
std::cout << "Equality!" << std::endl;
else
std::cout << "Not equality." << std::endl;
return 0;
}
它返回:
$ g++ test_dp.cpp -o test_dp.exe
$ ./test_dp.exe
x = 0.333333333333333314829616256247
y = 1
平等!
解决方案
假设您的double
类型符合IEEE 754,则 1.0/3.0 的十六进制表示为3FD5555555555555
. 这不完全是 1/3。它分解为:
- 符号 = 0(即数字为正)
- 有偏指数 =
3FD
(即指数 = -2) - 53 位尾数 =
15555555555555
(隐含前导1
)
乘以15555555555555
3 得到3FFFFFFFFFFFFF
。要将其压缩为 53 位,我们必须丢弃最低有效位,这(在大多数环境的默认舍入模式下)意味着尾数“舍入为偶数”:尾随二进制01
转到0
,而尾随二进制11
转到100
(意味着可以传播进位)。在这种情况下,进位一直传播到最高有效位,留40000000000000
在尾数中。我们希望第 52 位成为最高有效位,因此我们将其向下移动10000000000000
并将指数增加 2。最终结果是3FF0000000000000
,或者恰好是 1.0。
所以你的程序是正确的——一个不精确的结果乘以一个小整数会给你一个精确的结果。但人们可能会认为这更多是靠运气而不是判断:-)
推荐阅读
- android - Android后退箭头在点击时没有视觉反馈
- javascript - ContentEditable div 焦点。光标在 EDGE 和 IE 浏览器中上升一点
- certificate - NIFI - 禁用客户端证书请求
- google-bigquery - 从 bigquery 导入到 google 表格限制为 10k 行
- python - 当变量具有相同名称时从多级 XML 中提取数据子集
- java - 学生提交返回的奇怪用户 ID
- javascript - 目录当前不存在,安装过程将尝试创建它
- python - Python:如何使装饰器可选?
- azure-data-flow - Azure 数据工厂数据流表达式生成器
- python - scrapy中的Djangoitem导入问题