代码之家  ›  专栏  ›  技术社区  ›  Bob Cross n8wrl

有Java等价的FRIPXP吗?

  •  5
  • Bob Cross n8wrl  · 技术社区  · 15 年前

    是否有一个Java等价的C/C++函数称为 frexp 是吗?如果你不熟悉,frexp就是 defined by Wikipedia 将浮点数分解为尾数和指数。

    我正在寻找一个既有速度又有准确性的实现,但是如果我只能选择一个,我宁愿拥有准确性。

    这是第一个引用的代码示例。它应该让frexp合同更清楚一点:

    /* frexp example */
    #include <stdio.h>
    #include <math.h>
    
    int main ()
    {
      double param, result;
      int n;
    
      param = 8.0;
      result = frexp (param , &n);
      printf ("%lf * 2^%d = %f\n", result, n, param);
      return 0;
    }
    
    /* Will produce: 0.500000 * 2^4 = 8.000000 */
    
    6 回复  |  直到 14 年前
        1
  •  3
  •   Community CDub    7 年前

    这是怎么回事?

    public static class FRexpResult
    {
       public int exponent = 0;
       public double mantissa = 0.;
    }
    
    public static FRexpResult frexp(double value)
    {
       final FRexpResult result = new FRexpResult();
       long bits = Double.doubleToLongBits(value);
       double realMant = 1.;
    
       // Test for NaN, infinity, and zero.
       if (Double.isNaN(value) || 
           value + value == value || 
           Double.isInfinite(value))
       {
          result.exponent = 0;
          result.mantissa = value;
       }
       else
       {
    
          boolean neg = (bits < 0);
          int exponent = (int)((bits >> 52) & 0x7ffL);
          long mantissa = bits & 0xfffffffffffffL;
    
          if(exponent == 0)
          {
             exponent++;
          }
          else
          {
             mantissa = mantissa | (1L<<52);
          }
    
          // bias the exponent - actually biased by 1023.
          // we are treating the mantissa as m.0 instead of 0.m
          //  so subtract another 52.
          exponent -= 1075;
          realMant = mantissa;
    
          // normalize
          while(realMant > 1.0) 
          {
             mantissa >>= 1;
             realMant /= 2.;
             exponent++;
          }
    
          if(neg)
          {
             realMant = realMant * -1;
          }
    
          result.exponent = exponent;
          result.mantissa = realMant;
       }
       return result;
    }
    

    这是“灵感”,或者实际上几乎是从 answer 类似的问题。它与位一起工作,然后使尾数成为介于1.0和0.0之间的数字。

        2
  •  1
  •   Maurice Perry    15 年前

    请参见float.floatToIntBits和double.doubletOngBits。您仍然需要一些额外的逻辑来解码IEEE754浮点。

        3
  •  0
  •   jitter    15 年前

    这是你想要的。

    public class Test {
      public class FRex {
    
        public FRexPHolder frexp (double value) {
          FRexPHolder ret = new FRexPHolder();
    
          ret.exponent = 0;
          ret.mantissa = 0;
    
          if (value == 0.0 || value == -0.0) {
            return ret;
          }
    
          if (Double.isNaN(value)) {
            ret.mantissa = Double.NaN;
            ret.exponent = -1;
            return ret;
          }
    
          if (Double.isInfinite(value)) {
            ret.mantissa = value;
            ret.exponent = -1;
            return ret;
          }
    
          ret.mantissa = value;
          ret.exponent = 0;
          int sign = 1;
    
          if (ret.mantissa < 0f) {
            sign--;
            ret.mantissa = -(ret.mantissa);
          }
          while (ret.mantissa < 0.5f) {
            ret.mantissa *= 2.0f;
            ret.exponent -= 1;
          }
          while (ret.mantissa >= 1.0f) {
            ret.mantissa *= 0.5f;
            ret.exponent++;
          }
          ret.mantissa *= sign;
          return ret;
        }
      }
    
      public class FRexPHolder {
        int exponent;
        double mantissa;
      }
    
      public static void main(String args[]) {
        new Test();
      }
    
      public Test() {
        double value = 8.0;
        //double value = 0.0;
        //double value = -0.0;
        //double value = Double.NaN;
        //double value = Double.NEGATIVE_INFINITY;
        //double value = Double.POSITIVE_INFINITY;
    
        FRex test = new FRex();
        FRexPHolder frexp = test.frexp(value);
        System.out.println("Mantissa: " + frexp.mantissa);
        System.out.println("Exponent: " + frexp.exponent);
        System.out.println("Original value was: " + value);
        System.out.println(frexp.mantissa+" * 2^" + frexp.exponent + " = ");
        System.out.println(frexp.mantissa*(1<<frexp.exponent));
      }
    }
    
        4
  •  0
  •   Powerlord    15 年前

    如果我读得对…

    public class Frexp {
      public static void main (String[] args)
      {
        double param, result;
        int n;
    
        param = 8.0;
        n = Math.getExponent(param);
        //result = ??
    
        System.out.printf ("%f * 2^%d = %f\n", result, n, param);
      }
    }
    

    不幸的是,似乎没有一种内置的方法可以在不首先将尾数转换为bigdecimal的情况下获得尾数(或者只进行除法: result = param / Math.pow(2,n) .

    奇怪的是, scalb 正好相反:取尾数和指数,然后从中生成一个新的浮点。

        5
  •  -1
  •   RMorrisey    15 年前

    我不熟悉frexp函数,但我认为您需要查看 BigDecimal “缩放值和未缩放值。”无标度是精度的尾数,标度是指数。在psuedocode中:值=非标量10^(-scale)

        6
  •  -1
  •   non sequitor    15 年前

    不存在在核心Java中或在共享空间中的当前实现(最有可能找到其他地方),它具有完全相同的功能和易用性。 氟利浦 我知道的。如果它确实存在的话,它可能在一个不被广泛使用的工具箱中。