比较两个花车

问题描述 投票:9回答:5
#include <stdbool.h>

bool Equality(double a, double b, double epsilon)
{
  if (fabs(a-b) < epsilon) return true;
  return false;
}

我尝试这种方法来比较两个双打,但我总是遇到问题,因为我不知道如何选择epsilon,实际上我想比较小数字(小数点后6位数),如0.000001。我尝试了一些数字,有时我得到0.000001 != 0.000001,有时候0.000001 == 0.000002除了与epsilon比较之外还有其他方法吗?

我的目的是比较两个双打(代表我的情况下的时间)。表示以毫秒为单位的时间的变量t是double。每次t改变时,它会增加另一个函数0.000001然后0.000002等。我想检查它是否等于double tt类型的另一个变量,如果tt == t,我有一些指令要执行.. 谢谢你的帮助

c comparison
5个回答
16
投票

看这里:http://floating-point-gui.de/errors/comparison/

由于舍入错误,大多数浮点数最终略微不精确。只要这种不精确度保持很小,通常可以忽略它。但是,它也意味着预期相等的数字(例如,当通过不同的正确方法计算相同的结果时)通常略有不同,并且简单的相等测试失败。

当然,还有What Every Computer Scientist Should Know About Floating-Point Arithmetic


3
投票

第一:计算布尔值(使用<运算符)然后将其包装在另一个布尔值中是没有意义的。就像这样写:

bool Equality(float a, float b, float epsilon)
{
  return fabs(a - b) < epsilon;
}

其次,你的epsilon本身可能没有很好地表现为float,因此看起来不像你期望的那样。尝试使用2的负幂,例如1/1048576。


1
投票

或者,您可以比较两个整数。只需将您的两个浮点数乘以所需的精度,然后将它们转换为整数。务必正确地向上/向下舍入。这是它的样子:

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);
}

0
投票

请记住,当float a = +2^(254-127) * 1.___22 zeros___1float b = +2^(254-127) * 1.___23 zeros___然后我们期待abs(a-b) < epsilon而不是a - b = +2^(254-127-23) * 1.___23 zeros___ = 20282409603651670423947251286000比epsilon大得多...


0
投票

我编写并测试了这段代码。看起来很有效。

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; }
  • 如果任何数字是NaN,则数字不相等。
  • 如果2个数字相同,则相等。这是一个快速的初步检查。
  • 如果两个数字都是+ 0,-0或次正规,则数字相等。
  • 如果数字有不同的符号,则数字不相等。如果两个数字几乎为0(但不是±0或次正规)且具有不同的符号,则这看起来是错误的方法。但是如果你把这些数字乘以另一个呢?一个结果是负面的而另一个是积极的。所以我们是严格的,这是对的。
  • 如果指数有2个或更多的差异,则数字不相等,因为一个数字至少是另一个数字的2倍。
  • 如果指数恰好为1,则从其中一个数字正确移位分数。
  • 如果2个分数的差异很小,则数字相等。
© www.soinside.com 2019 - 2024. All rights reserved.