我需要一些必须准确的浮动分区,就像它们的双重版本一样。我可以改变分割值 - 它代表一个映射,我可以抵消它 - 来纠正最终的浮点错误。
为了纠正错误,我使用了以下代码:
do
{
float fValue = float(x) / 1024.f;
double oldFValue = fValue;
double dValue = double(x) / 1024.0;
if(oldFValue != dValue)
{
x += 1;
}
else
{
break;
}
}while(1);
使用此代码,
x = 11
我有调试器(Visual Studio 2010):
fValue = 0.010742188
oldFValue = 0.010742187500000000
您能否解释为什么可移动值与浮动值不同?这是调试器问题还是浮点转换问题?我问这个是因为:
if(oldFValue != dValue)
永远不会是真的,即使它应该是。我可以用其他方式比较浮点值和双值吗?我需要浮点除法的结果与双除法完全相同。
答案 0 :(得分:10)
答案 1 :(得分:2)
您对single precision float了解多少?
它存储为<sign><exponent><mantis>
。您可以将最终号码写为:
(sign ? 1 : -1) * 0.1<mantis> * 2^(expontent - 127)
正如您所见,数字始终存储为数字>1
和二进制分数。不幸的是,0.1 dec
这样的某些数字是二进制的,因此您不会使用float获得精确的结果。
您可以尝试使用此功能:if(oldFValue != (float)dValue)
如果它不能正常工作,您也可以尝试:
if(oldFValue*32 != (float)dValue*32)
这将导致:
mantis >> 5
expontent += 5
这可能会消除您的错误(尝试1(很奇怪,但在某些情况下可能有效),2,4,8,16 ......,2 ^ n)。
编辑:明确阅读Johnsywebs link
答案 2 :(得分:2)
11/1024在float
和double
中都可以完全表示。当然是oldFValue == dValue
。
答案 3 :(得分:1)
浮点问题在于任何非单一范围都存在无限数量的有理数。但是,您只有有限位数来表示您的浮点数。
因此 - 浮点数不是实数/有理数 - 并且表现不同。你应该期望它不是一个真实的数字。
因此,您永远不应使用operator==
检查浮点的相等性。你应该计算delta=abs(num1-num2)
,并检查它是否小于你可以容忍其错误的某个值。
正如@Johnsyweb所说,阅读和理解所附文章对于正确处理浮点非常重要。
答案 4 :(得分:1)
大多数浮点运算都是在尾数数据丢失的情况下执行的,即使组件很好地适合它(数字如0.5或0.25)。 例如
a + c + b
与
不同#include <stdio.h>
// Helpers declaration, for implementation scroll down
float getAllOnes(unsigned bits);
unsigned getMantissaBits();
int main() {
// Determine mantissa size in bits
unsigned mantissaBits = getMantissaBits();
// Considering mantissa has only 3 bits, we would then get:
// a = 0b10 m=1, e=1
// b = 0b110 m=11, e=1
// c = 0b1000 m=1, e=3
// a + b = 0b1000, m=100, e=1
// a + c = 0b1010, truncated to 0b1000, m=100, e=1
// a + b + c result: 0b1000 + 0b1000 = 0b10000, m=100, e=2
// a + c + b result: 0b1000 + 0b110 = 0b1110, m=111, e=1
float a = 2,
b = getAllOnes(mantissaBits) - 1,
c = b + 1;
float ab = a + b;
float ac = a + c;
float abc = a + b + c;
float acb = a + c + b;
printf("\n"
"FP partial invariance issue demo:\n"
"\n"
"Mantissa size = %i bits\n"
"\n"
"a = %.1f\n"
"b = %.1f\n"
"c = %.1f\n"
"(a+b) result: %.1f\n"
"(a+c) result: %.1f\n"
"(a + b + c) result: %.1f\n"
"(a + c + b) result: %.1f\n"
"---------------------------------\n"
"diff(a + b + c, a + c + b) = %.1f\n\n",
mantissaBits,
a, b, c,
ab, ac,
abc, acb,
abc - acb);
return 1;
}
// Helpers
float getAllOnes(unsigned bits) {
return (unsigned)((1 << bits) - 1);
}
unsigned getMantissaBits() {
unsigned sz = 1;
unsigned unbeleivableHugeSize = 1024;
float allOnes = 1;
for (;sz != unbeleivableHugeSize &&
allOnes + 1 != allOnes;
allOnes = getAllOnes(++sz)
) {}
return sz-1;
}
多个操作组件的顺序也很重要。
为了解决必要的问题,了解机器如何表示fp数字。
也许这会有所帮助: http://stepan.dyatkovskiy.com/2018/04/machine-fp-partial-invariance-issue.html
以下是+ b + c问题的C示例。祝你好运!
example.c
[33.33, 33.33, 33.33]