2009-10-12 84 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

相關問題