比较IEEE浮点数和双精度数据的最佳方法是什么?我听说过几种方法,但我想看看社区的想法。
答案 0 :(得分:7)
我认为最好的方法是比较ULPs。
bool is_nan(float f)
{
return (*reinterpret_cast<unsigned __int32*>(&f) & 0x7f800000) == 0x7f800000 && (*reinterpret_cast<unsigned __int32*>(&f) & 0x007fffff) != 0;
}
bool is_finite(float f)
{
return (*reinterpret_cast<unsigned __int32*>(&f) & 0x7f800000) != 0x7f800000;
}
// if this symbol is defined, NaNs are never equal to anything (as is normal in IEEE floating point)
// if this symbol is not defined, NaNs are hugely different from regular numbers, but might be equal to each other
#define UNEQUAL_NANS 1
// if this symbol is defined, infinites are never equal to finite numbers (as they're unimaginably greater)
// if this symbol is not defined, infinities are 1 ULP away from +/- FLT_MAX
#define INFINITE_INFINITIES 1
// test whether two IEEE floats are within a specified number of representable values of each other
// This depends on the fact that IEEE floats are properly ordered when treated as signed magnitude integers
bool equal_float(float lhs, float rhs, unsigned __int32 max_ulp_difference)
{
#ifdef UNEQUAL_NANS
if(is_nan(lhs) || is_nan(rhs))
{
return false;
}
#endif
#ifdef INFINITE_INFINITIES
if((is_finite(lhs) && !is_finite(rhs)) || (!is_finite(lhs) && is_finite(rhs)))
{
return false;
}
#endif
signed __int32 left(*reinterpret_cast<signed __int32*>(&lhs));
// transform signed magnitude ints into 2s complement signed ints
if(left < 0)
{
left = 0x80000000 - left;
}
signed __int32 right(*reinterpret_cast<signed __int32*>(&rhs));
// transform signed magnitude ints into 2s complement signed ints
if(right < 0)
{
right = 0x80000000 - right;
}
if(static_cast<unsigned __int32>(std::abs(left - right)) <= max_ulp_difference)
{
return true;
}
return false;
}
类似的技术可用于双打。诀窍是转换浮点数以便它们被排序(就像整数一样),然后看看它们有多么不同。
我不知道为什么这个该死的东西搞砸了我的下划线。编辑:哦,也许这只是预览的人工制品。那没关系。
答案 1 :(得分:3)
我正在使用的当前版本是
bool is_equals(float A, float B,
float maxRelativeError, float maxAbsoluteError)
{
if (fabs(A - B) < maxAbsoluteError)
return true;
float relativeError;
if (fabs(B) > fabs(A))
relativeError = fabs((A - B) / B);
else
relativeError = fabs((A - B) / A);
if (relativeError <= maxRelativeError)
return true;
return false;
}
这似乎通过组合相对和绝对容错来解决大多数问题。 ULP方法更好吗?如果是这样,为什么?
答案 2 :(得分:1)
@DrPizza:我不是性能大师,但我希望定点操作比浮点运算更快(在大多数情况下)。
这取决于你在做什么。与IEEE浮点数相同的定点类型将慢很多倍(并且要大很多倍)。
适用于花车的东西:
3D图形,物理/工程,模拟,气候模拟......
答案 3 :(得分:1)
在数值软件中,您经常要测试两个浮点数是否完全相等。 LAPACK充满了这种情况的例子。当然,最常见的情况是您要测试浮点数是否等于“零”,“一”,“二”,“一半”。如果有人有兴趣,我可以选择一些算法并详细介绍。
同样在BLAS中,您经常需要检查浮点数是否恰好为零或一。例如,例程dgemv可以计算表单
的操作因此,如果beta等于一,你有一个“加号赋值”,而beta等于零则是一个“简单赋值”。因此,如果您对这些(常见)案例进行特殊处理,您当然可以降低计算成本。
当然,您可以设计BLAS例程,以避免精确比较(例如使用一些标志)。但是,LAPACK充满了无法实现的示例。
P.S:
肯定有很多情况下你不想检查“完全相同”。对于许多人来说,这甚至可能是他们唯一需要处理的案例。我想指出的是,还有其他案例。
虽然LAPACK是用Fortran编写的,但如果您使用其他编程语言编写数字软件,逻辑也是一样的。
答案 4 :(得分:0)
哦,亲爱的领主,请不要将浮动位解释为整数,除非您在P6或更早版本上运行。
答案 5 :(得分:0)
哦,亲爱的领主,请不要将浮动位解释为整数,除非您在P6或更早版本上运行。
即使它导致它通过内存从向量寄存器复制到整数寄存器,即使它停止了管道,这是我遇到的最好的方法,因为它提供了最强大的比较甚至面对浮点错误。
即。这是一个值得付出的代价。
答案 6 :(得分:0)
这是我遇到过的最好的方法,因为它提供了最强大的比较,即使面对浮点错误。
如果您有浮点错误,那么您遇到的问题就更多了。虽然我认为这取决于个人观点。
答案 7 :(得分:0)
这似乎通过组合相对和绝对容错来解决大多数问题。 ULP方法更好吗?如果是这样,为什么?
ULP是两个浮点数之间“距离”的直接度量。这意味着它们不需要您想出相对和绝对错误值,也不必确保将这些值“约为正确”。使用ULP,您可以直接表达您希望数字的接近程度,同样的阈值也适用于小值和大值。
答案 8 :(得分:0)
如果您有浮点错误,那么您遇到的问题就更多了。虽然我认为这取决于个人观点。
即使我们进行数值分析以最大限度地减少误差累积,我们也无法消除它,我们可以留下应该相同的结果(如果我们用实数计算)但不同(因为我们无法用实数)。
答案 9 :(得分:0)
如果你正在寻找两个花车相同,那么在我看来它们应该完全相同。如果您遇到浮点舍入问题,也许固定点表示更适合您的问题。
答案 10 :(得分:0)
如果你正在寻找两个花车相同,那么在我看来它们应该完全相同。如果您遇到浮点舍入问题,也许固定点表示更适合您的问题。
也许我们无法承受这种方法会造成的范围或性能的损失。
答案 11 :(得分:0)
如果你正在寻找两个花车相同,那么在我看来它们应该完全相同。如果您遇到浮点舍入问题,也许固定点表示更适合您的问题。
也许我应该更好地解释这个问题。在C ++中,以下代码:
#include <iostream>
using namespace std;
int main()
{
float a = 1.0;
float b = 0.0;
for(int i=0;i<10;++i)
{
b+=0.1;
}
if(a != b)
{
cout << "Something is wrong" << endl;
}
return 1;
}
打印短语“Something is wrong”。你是说它应该吗?
答案 12 :(得分:0)
@DrPizza:我不是性能大师,但我希望定点操作比浮点运算更快(在大多数情况下)。
@Craig H:好的。我打印它完全没问题。如果a或b存钱,那么它们应该以固定点表示。我正在努力想到一个真实世界的例子,这种逻辑应该与浮动联合起来。适合花车的东西:
对于所有这些事情,要么你数字很多,只是简单地将结果呈现给用户进行人工解释,或者你做一个比较陈述(即使这样的陈述是,“这个事情在这另一件事的0.001之内” )。像我这样的比较语句仅在算法的上下文中有用:“0.001以内”部分取决于您所询问的物理问题。我的0.02。或者我应该说2/100?
答案 13 :(得分:0)
这取决于你是什么 和他们一起做。定点类型 与IEEE float相同的范围 将慢很多倍(和 多倍)。
好的,但是如果我想要一个无限小的比特分辨率,那么它又回到了原点:==和!=在这样的问题的背景下没有意义。
一个int让我表达~10 ^ 9个值(无论范围如何),这似乎足以满足任何我关心其中两个相等的情况。如果这还不够,请使用64位操作系统,你有大约10 ^ 19个不同的值。
我可以在int中表示0到10 ^ 200(例如)范围内的值,它只是遭受的位分辨率(分辨率大于1,但同样,没有应用程序具有那种类型范围以及那种解决方案)。
总而言之,我认为在所有情况下,一个或者代表一个连续的值,在这种情况下!=和==是无关的,或者一个代表一组固定的值,可以映射到一个int(或者另一种固定精度型)。
答案 14 :(得分:0)
一个int让我表达~10 ^ 9个值 看来(不论范围如何) 对我任何情况都足够了 会关心他们中的两个 等于。如果这还不够,请使用 64位操作系统,你有大约10 ^ 19 不同的价值观。
我实际上达到了这个极限......我试图在模拟中以时钟周期的ps和时间来兼顾时间,你可以轻松地达到10 ^ 10个周期。无论我做了什么,我都很快就溢出了64位整数的微弱范围... 10 ^ 19并不像你想象的那么多,现在计算128位计算!
Floats允许我得到数学问题的解决方案,因为值在低端溢出了很多零。所以你基本上在数字中有一个小数点浮动aronud而没有精度损失(我可以想象浮点数的尾数中允许的值与64位int相比更有限,但是迫切需要th范围! )。
然后将事物转换回整数进行比较等。
烦人,最后我取消了整个尝试,只依靠浮子和&lt;和&gt;完成工作。不完美,但适用于设想的用例。