C语言 比较两个浮点数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5989191/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Compare two floats
提问by kate
#include <stdbool.h>
bool Equality(double a, double b, double epsilon)
{
if (fabs(a-b) < epsilon) return true;
return false;
}
I tried this method to compare two doubles, but I always get problems since I don't know how to chose the epsilon, actually I want to compare small numbers (6 6 digits after the decimal point) like 0.000001. I tried with some numbers, sometimes I get 0.000001 != 0.000001and sometimes 0.000001 == 0.000002Is there another method else than comparing with the epsilon?
我尝试过这种方法来比较两个双打,但我总是遇到问题,因为我不知道如何选择epsilon,实际上我想比较像0.000001这样的小数(小数点后 6 位)。我尝试了一些数字,有时我得到0.000001 != 0.000001,有时0.000001 == 0.000002除了与 epsilon 比较之外还有其他方法吗?
My purpose is to compare two doubles (which represent the time in my case). The variable t which represents the time in milliseconds is a double. It is incremented by another function 0.000001 then 0.000002 etc. each time t changes, I want to check if it is equal to another variable of type double tt, in case tt == t, I have some instructions to execute..
Thanks for your help
我的目的是比较两个双打(在我的情况下代表时间)。以毫秒为单位表示时间的变量 t 是一个双精度值。它由另一个函数 0.000001 然后 0.000002 等递增。每次 t 更改时,我想检查它是否等于另一个 double tt 类型的变量,以防 tt == t,我有一些指令要执行..
谢谢你帮助
回答by Roddy
Look here: http://floating-point-gui.de/errors/comparison/
看这里:http: //floating-point-gui.de/errors/comparison/
Due to rounding errors, most floating-point numbers end up being slightly imprecise. As long as this imprecision stays small, it can usually be ignored. However, it also means that numbers expected to be equal (e.g. when calculating the same result through different correct methods) often differ slightly, and a simple equality test fails.
由于舍入错误,大多数浮点数最终会稍微不精确。只要这种不精确性保持很小,它通常可以被忽略。但是,这也意味着期望相等的数字(例如,通过不同的正确方法计算相同结果时)通常略有不同,并且简单的相等性测试失败。
And, of course, What Every Computer Scientist Should Know About Floating-Point Arithmetic
回答by unwind
First: there's no point in computing a boolean value (with the <operator) and then wrapping that in another boolean. Just write it like this:
首先:计算一个布尔值(使用<运算符)然后将其包装在另一个布尔值中是没有意义的。就这样写:
bool Equality(float a, float b, float epsilon)
{
return fabs(a - b) < epsilon;
}
Second, it's possible that your epsilon itself isn't well-represented as a float, and thus doesn't look like what you expect. Try with a negative power of 2, such as 1/1048576 for instance.
其次,您的 epsilon 本身可能没有很好地表示为float,因此看起来不像您期望的那样。尝试使用 2 的负幂,例如 1/1048576。
回答by rebs01
Alternatively, you could compare two integers instead. Just multiply your two floats by the desired precision and cast them to integers. Be sure to round up/down correctly. Here is what it looks like:
或者,您可以比较两个整数。只需将您的两个浮点数乘以所需的精度并将它们转换为整数。确保正确向上/向下舍入。这是它的样子:
BOOL floatcmp(float float1, float float2, unsigned int precision){
int int1, int2;
if (float1 > 0)
int1 = (int)(float1 * precision + .5);
else
int1 = (int)(float1 * precision - .5);
if (float2 > 0)
int2 = (int)(float2 * precision + .5);
else
int2 = (int)(float2 * precision - .5);
return (int1 == int2);
}
回答by Chameleon
Keep in mind that when float a = +2^(254-127) * 1.___22 zeros___1and float b = +2^(254-127) * 1.___23 zeros___then we expect abs(a-b) < epsilonbut instead a - b = +2^(254-127-23) * 1.___23 zeros___ = 20282409603651670423947251286000which is much bigger than epsilon...
请记住,当float a = +2^(254-127) * 1.___22 zeros___1且float b = +2^(254-127) * 1.___23 zeros___然后我们预计abs(a-b) < epsilon而是a - b = +2^(254-127-23) * 1.___23 zeros___ = 20282409603651670423947251286000比小量大得多...
回答by Chameleon
I write and test this code. It seems working.
我编写并测试了这段代码。它似乎工作。
public static boolean equal(double a, double b) {
final long fm = 0xFFFFFFFFFFFFFL; // fraction mask
final long sm = 0x8000000000000000L; // sign mask
final long cm = 0x8000000000000L; // most significant decimal bit mask
long c = Double.doubleToLongBits(a), d = Double.doubleToLongBits(b);
int ea = (int) (c >> 52 & 2047), eb = (int) (d >> 52 & 2047);
if (ea == 2047 && (c & fm) != 0 || eb == 2047 && (d & fm) != 0) return false; // NaN
if (c == d) return true; // identical - fast check
if (ea == 0 && eb == 0) return true; // ±0 or subnormals
if ((c & sm) != (d & sm)) return false; // different signs
if (abs(ea - eb) > 1) return false; // b > 2*a or a > 2*b
d <<= 12; c <<= 12;
if (ea < eb) c = c >> 1 | sm;
else if (ea > eb) d = d >> 1 | sm;
c -= d;
return c < 65536 && c > -65536; // don't use abs(), because:
// There is a posibility c=0x8000000000000000 which cannot be converted to positive
}
public static boolean zero(double a) { return (Double.doubleToLongBits(a) >> 52 & 2047) < 3; }
- if any of the numbers is NaN, numbers are unequal.
- if 2 numbers are identical, are equal. This is a fast initial check.
- if both numbers are any of +0, -0 or subnormal, numbers are equal.
- if numbers have different signs, numbers are unequal. This looks like a wrong approach if both numbers are almost 0 (but not ±0 or subnormals) with different signs. But what if you multiply these numbers with another? one result will be negative and the other positive. So we are strict and this is right.
- if exponents have difference 2 or more, numbers are unequal, because one number is at least 2 times greater than the other.
- if exponents have difference exactly 1, shift correctly the fraction from one of the numbers.
- If difference of 2 fractions is small, numbers are equal.
- 如果任何数字为 NaN,则数字不相等。
- 如果两个数字相同,则相等。这是一个快速的初始检查。
- 如果两个数字都是 +0、-0 或次正常中的任何一个,则数字相等。
- 如果数字有不同的符号,则数字不相等。如果两个数字都几乎为 0(但不是 ±0 或次正态)且符号不同,则这看起来像是一种错误的方法。但是如果你将这些数字与另一个数字相乘呢?一个结果为阴性,另一个为阳性。所以我们很严格,这是对的。
- 如果指数相差 2 或更多,则数字不相等,因为一个数字至少比另一个大 2 倍。
- 如果指数的差恰好为 1,则从其中一个数字中正确移动分数。
- 如果两个分数的差异很小,则数字相等。

