2009-10-12 79 views
5

是否存在称为frexp的C/C++函数的Java等价物?如果你不熟悉,frexp是defined by Wikipedia“将浮点数分解为尾数和指数。”是否有与frexp相当的Java?

我正在寻找速度和精度的实施,但我宁愿有准确性,如果我只能选择一个。

这是第一次参考的代码示例。它应使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 */ 
+0

我认为Apache Commons Math软件包可能是一个很好的找到它的地方,但我没有看到任何东西。也许你可以为它提供一个功能请求?或者,如果您决定自己编写代码,请与他们谈论将其包含在图书馆中 - 这对我来说似乎是一个有益的补充。 – Carl 2009-10-12 16:14:57

+0

@Carl,我同意这会有用。尽管我非常了解自己和工作量,所以我不会承诺试图单独创建它。我敢肯定,我可以做80%的工作正确的时间,我必须投入80%,这是非常接近坏比无用.... – 2009-10-12 20:22:07

+0

真正的问题是:为什么frexp不会打破浮动到两个整数,但至少需要一个浮动..对于一个没有意义的浮点分解(想想递归.....) – 2009-10-13 21:51:53

回答

3

这个怎么

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复制到一个类似的C#问题。它与位一起工作,然后使尾数在1.0和0.0之间。

+0

Yikes!上面的代码不太正确:它应该是while(realMant> = 1.0)而不是while(realMant> 1.0)。返回值的大小必须在1/2(包含)到1(不包括)的范围内,请参见[GNU libc手册](http://www.gnu.org/software/libc/manual/html_node/Normalization -Functions.html)。使用上面的代码,frexp(1.0)将错误地返回1.0而不是0.5。 – akbertram 2015-11-26 11:35:14

-1

我不熟悉的frexp功能,但我认为你需要看看BigDecimal'缩放和未缩放值。 'unscaled'是精度尾数,scale是指数。在psuedocode中:value = unscaledValue 10 ^( - scale)

1

请参阅Float.floatToIntBits和Double.doubleToLongBits。您仍然需要一些额外的逻辑来解码IEEE 754浮点。

+0

谢谢 - 我知道有能力得到这些位。我所关心的不是从位集合中解析s,e和m的基本情况。我更担心完全实施frexp,维护处理所有角落案例的合同(例如NaN的不同风格)。 – 2009-10-12 13:19:11

0

这是做你想做的。

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

@jitter,谢谢,但frexp实际上与IEEE浮点标准的位一起工作,而不是试图推导出数学结果。这是这个问题的目标。 – 2009-10-13 21:34:10

-1

都能跟得上存在核心Java或在下议院郎目前没有实现(最有可能的其他地方找到它),具有完全相同的功能和易用性frexp的;我知道的。如果确实存在,它可能是一个未被广泛使用的工具包。

0

如果我读这个权利......

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不完全相反:取尾数和指数,并生成一个新的浮动

+0

@R。 Bemrose,这个练习的重点不是转化。相反,该函数采用IEEE标准浮点表示并对其进行解码。目标不是想出一个似乎给出相同答案的数学表达式。 – 2009-10-14 01:37:54

相关问题