代码之家  ›  专栏  ›  技术社区  ›  Owen

如何通过其最小增量(或接近增量)更改浮点?

  •  46
  • Owen  · 技术社区  · 17 年前

    double f 并希望有一种方法将其稍微增大(或减小),以获得一个新值,该值将尽可能接近原始值,但仍然严格大于(或小于)原始值。

    7 回复  |  直到 17 年前
        1
  •  65
  •   Nils Pipenbrinck    12 年前

    检查您的math.h文件。如果你幸运的话,你有 nextafter nextafterf 定义的函数。它们以可移植且独立于平台的方式完全满足您的需求,并且是C99标准的一部分。

    另一种方法(可能是后备解决方案)是将浮点分解为尾数和指数部分。递增很容易:只需在尾数上加一个。如果出现溢出,则必须通过增加指数来处理。递减也是如此。

    简而言之,这和nextafter做的事情是一样的。

    不过,这不会是完全可移植的。您必须处理endianess和并非所有机器都有IEEE浮点的事实(好的,最后一个原因更具学术性)。

        2
  •  23
  •   Mike F Mike F    17 年前
    u64 &x = *(u64*)(&f);
    x++;
    

    是的,说真的。

    u64 &x = *(u64*)(&f);
    if( ((x>>52) & 2047) != 2047 )    //if exponent is all 1's then f is a nan or inf.
    {
        x += f>0 ? 1 : -1;
    }
    
        3
  •  6
  •   moonshadow    17 年前

    就绝对值而言,可以添加到浮点值以生成新的不同值的最小量将取决于该值的当前大小;这将是该类型的 machine epsilon 乘以当前指数。

    查看 IEEE spec 用于浮点表示。最简单的方法是将该值重新解释为整数类型,添加1,然后检查(如果您愿意)是否没有翻转符号或通过检查符号和指数位生成NaN。

    frexp 获取当前尾数和指数,从而计算要添加的值。

        4
  •  2
  •   Jim Buck    17 年前

    double DoubleIncrement(double value)
    {
      int exponent;
      double mantissa = frexp(value, &exponent);
      if(mantissa == 0)
        return DBL_MIN;
    
      mantissa += DBL_EPSILON/2.0f;
      value = ldexp(mantissa, exponent);
      return value;
    }
    
        5
  •  0
  •   TheSoftwareJedi jac    17 年前

    值得一提的是,标准++递增停止工作的值是9007199254740992。

        6
  •  0
  •   luke    17 年前

    这可能不是你想要的,但你仍然可以找到 numeric_limits 正在使用中。尤其是min()和epsilon()成员。

    我不相信像mydouble+numeric_limits::epsilon()这样的东西会做你想做的事情,除非mydouble已经接近epsilon了。如果是的话,那么你很幸运。

        7
  •  -2
  •   C. K. Young    17 年前

    我不久前发现了这段代码,也许它可以帮助你确定你能推它的最小值,然后再增加这个值。不幸的是,我记不起此代码的参考:

    #include <stdio.h>
    
    int main()
    {
        /* two numbers to work with */
        double number1, number2;    // result of calculation
        double result;
        int counter;        // loop counter and accuracy check
    
        number1 = 1.0;
        number2 = 1.0;
        counter = 0;
    
        while (number1 + number2 != number1) {
            ++counter;
            number2 = number2 / 10;
        }
        printf("%2d digits accuracy in calculations\n", counter);
    
        number2 = 1.0;
        counter = 0;
    
        while (1) {
            result = number1 + number2;
            if (result == number1)
                break;
            ++counter;
            number2 = number2 / 10.0;
        }
    
        printf("%2d digits accuracy in storage\n", counter );
    
        return (0);
    }