c++ - 浮点精度在测试变量是否达到界限时的影响
问题描述
我有一个 C/C++ 函数 checkt (FLT t),其中 FLT 是由预处理器设置的浮点精度,我想在更大的代码体中使用它以确保传递给它的值在 [0,1 ]。它通常用于通过固定增量增加变量 checkt 当参数超出范围时会出错。在这个简单的示例中,我想以 0.1 为增量从 0.0 变为 1.0。但是,由于 0.1 并不能完美地表示为 0.1000000000 等以达到精度极限,因此我将在循环结束时准确地获得值 1.0。如果 FLT 设置为 double,则下面的代码片段有效,但如果设置为 float,则无效。我还附加了两者的输出。编译器为 gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0。
#include <vector>
#include <iostream>
#define FLT double
void checkt (FLT t) {
if (t < FLT{0} || t > FLT{1}) {
std::cout << "t before error = " << t << std::endl;
throw std::runtime_error ("t out of range [0,1]");
}
}
int main(int argc, char **argv) {
FLT x = FLT{0.0};
FLT inc = FLT{0.1};
FLT y = FLT{1};
std::cout.precision(16);
std::cout << "x is " << x << "y is " << y << " inc is " << inc << std::endl;
for (int i=0; i<11; i++){
std::cout.precision(16);
std::cout << "x is " << x << std::endl;
checkt(x);
x += inc;
}
return 0;
}
FLT=double x 的输出是 0y 是 1 inc 是 0.1
x is 0
x is 0.1
x is 0.2
x is 0.3
x is 0.4
x is 0.5
x is 0.6
x is 0.7
x is 0.7999999999999999
x is 0.8999999999999999
x is 0.9999999999999999
FLT = float 的输出是
y is 1 inc is 0.1000000014901161
x is 0
x is 0.1000000014901161
x is 0.2000000029802322
x is 0.300000011920929
x is 0.4000000059604645
x is 0.5
x is 0.6000000238418579
x is 0.7000000476837158
x is 0.8000000715255737
x is 0.9000000953674316
x is 1.00000011920929
t before error = 1.00000011920929
terminate called after throwing an inst
解决方案
由于二进制浮点的不精确性质,循环的每次迭代中的重复加法可能会导致误差因子随着时间的推移而累积。
不要x
在每次迭代中添加增量,而是将增量乘以循环索引并设置x
为该值。
for (int i=0; i<11; i++){
x = inc * i;
std::cout.precision(17);
std::cout << "x is " << x << std::endl;
checkt(x);
}
输出double
:
x is 0y is 1 inc is 0.1
x is 0
x is 0.10000000000000001
x is 0.20000000000000001
x is 0.30000000000000004
x is 0.40000000000000002
x is 0.5
x is 0.60000000000000009
x is 0.70000000000000007
x is 0.80000000000000004
x is 0.90000000000000002
x is 1
输出float
:
x is 0y is 1 inc is 0.1000000014901161
x is 0
x is 0.10000000149011612
x is 0.20000000298023224
x is 0.30000001192092896
x is 0.40000000596046448
x is 0.5
x is 0.60000002384185791
x is 0.69999998807907104
x is 0.80000001192092896
x is 0.90000003576278687
x is 1
推荐阅读
- c# - 如何从控制台读取矩阵并打印所有矩阵元素的总和
- python - 在用户级别分组并编码分类数据
- android - 如何将一个视图放在另一个视图的顶部,两个视图的中心在约束布局中对齐?
- python - 附加到关联数组
- sql-server - 有条件地替换计算中的变量
- c++ - 将 c-string 发送到非左值 std::ostringstream 奇怪的行为
- java - 多线程执行时,Oracle 合并查询因休眠事务中的唯一约束而失败
- fortran - 如何使用 macports 安装 HDF5、openMPI .mod 文件?
- c - 缓冲区溢出不生成外壳?
- jhipster - 将 jhipster 与 ngx-admin 集成