浮点运算
Floating point Arithmetics
今天在我的C++编程课上,我的教授告诉我,永远不应该直接比较两个浮点值。
所以我尝试了这段代码,并找出了他陈述的原因。
double l_Value=94.9;
print("%.20lf",l_Value);
我发现结果为 94.899999999(一些相对错误)
我知道浮点数不是以呈现给代码的方式存储的。以二进制形式压缩这些 1 和 0 涉及一些相对舍入误差。
我正在寻找两个问题的解决方案。 1. 比较两个浮点值的有效方法。 2. 如何将浮点值添加到另一个浮点值。例。将 0.1111 添加到 94.4345 以获得确切值 94.5456
提前谢谢。
- 比较两个浮点值的有效方法。
简单的double a,b; if (a == b)
是比较两个浮点值的有效方法。 然而,正如OP所注意到的,这可能不符合整体编码目标。 更好的方法取决于比较的上下文,OP不提供。 见下文。
- 如何将浮点值添加到另一个浮点值。例。将 0.1111 添加到 94.4345 以获得确切值 94.5456
作为源代码的浮点值具有有效的无限范围和精度,例如1.23456789012345678901234567890e1234567
。 将此文本转换为double
通常仅限于 264个不同值之一。 选择最接近的,但这可能不完全匹配。
这两种0.1111, 94.4345, 94.5456
都不能完全代表典型的double
。
OP 有以下选择:
1.) 使用除double, float
以外的其他类型。 各种库提供十进制浮点类型。
2)将代码限制为支持double
的稀有平台,以10为基数的形式,以便FLT_RADIX == 10
。
3) 编写自己的代码来处理用户输入,例如"0.1111"
到结构/字符串中并执行所需的操作。
4) 将用户输入视为字符串并转换为某种整数类型,再次使用支持的例程进行读取/计算/写入。
5)接受浮点运算在数学上不精确并处理舍入误差。
double a = 0.1111;
printf("a: %.*en", DBL_DECIMAL_DIG -1 , a);
double b = 94.4345;
printf("b: %.*en", DBL_DECIMAL_DIG -1 , b);
double sum = a + b;
printf("sum: %.*en", DBL_DECIMAL_DIG -1 , sum);
printf("%.4fn", sum);
输出
a: 1.1110000000000000e-01
b: 9.4434500000000000e+01
sum: 9.4545599999999993e+01
94.5456 // Desired textual output based on a rounded `sum` to the nearest 0.0001
更多关于 #1
如果不寻求确切的比较,而是寻求某种"两个值是否足够接近?",则需要"足够接近"的定义 - 其中有很多。
下面的"足够接近"通过检查两个数字的ULP来比较距离。 当值处于相同的 2 次方时,这是一个线性差异,并且在其他方面变为对数。 当然,改变标志是一个问题。
float
示例:
考虑从最负到最正的所有有限float
。 以下有点可移植的代码为具有相同顺序的每个float
返回一个整数。
uint32_t sequence_f(float x) {
union {
float f;
uint32_t u32;
} u;
assert(sizeof(float) == sizeof(uint32_t));
u.f = x;
if (u.u32 & 0x80000000) {
u.u32 ^= 0x80000000;
return 0x80000000 - u.u32;
}
return u.u3
}
现在,要确定两个float
是否"足够接近",只需比较两个整数。
static bool close_enough(float x, float y, uint32_t ULP_delta) {
uint32_t ullx = sequence_f(x);
uint32_t ully = sequence_f(y);
if (ullx > ully) return (ullx - ully) <= ULP_delta;
return (ully - ullx) <= ULP_delta;
}
我通常这样做的方法是有一个自定义的相等比较函数。 基本的想法是,你有一定的公差,比如0.0001什么的。 然后你减去你的两个数字并取它们的绝对值,如果它小于你的容差,你把它视为相等。 当然,还有其他策略可能更适合某些情况。
-
为自己定义一个公差级别
e
(例如,e=.0001
),并检查是否abs(a-b) <= e
-
您不会获得带有浮点数的"精确"值。 曾。 如果你事先知道你正在使用四个小数,并且你想要"精确",那么你需要在内部将你的数字视为整数,只将它们显示为小数。 944345 + 1111 = 945456
- 使用双精度的浮点运算
- 将异常字符串解析为向量上的浮点运算?
- -O1改变浮点运算
- 将浮点运算与 Z3 C++ API 结合使用
- C++模运算符,使用 #define 和自己的类进行浮点运算
- 浮点运算
- 浮点运算的精度
- 为什么GDB对浮点运算的评估与C++不同
- C中的浮点运算出错
- 在Visual C++中,浮点运算优化会导致罕见而奇怪的行为
- 为什么十进制浮点运算的提议没有被 C++0x 接受?
- 为什么这个浮点运算被编译得如此奇怪(没有经过优化)
- 浮点运算结果的重现性
- 在浮点运算上执行平方运算和平方根运算时:表达式必须具有整型或非整型枚举类型
- C++:浮点运算的稳定性策略
- 自动获取某些代码段的浮点运算计数的方法
- 用于浮点运算的快速、基于秩的基数排序
- 浮点运算中的整数转换
- 浮点运算是如何在一个大数字上加一的
- 使用浮点运算时,如何获得一致的程序行为