2009-10-12 26 views
5

Czy istnieje odpowiednik Javy dla funkcji C/C++ o nazwie frexp? Jeśli nie jesteś obeznany, frexp to defined by Wikipedia, aby "zepsuć liczbę zmiennoprzecinkową w mantysę i wykładnik".Czy istnieje odpowiednik frexp w języku Java?

Szukam wdrożenia z szybkością i dokładnością, ale wolałabym mieć dokładność, gdybym tylko mogła wybrać.

To jest przykład kodu z pierwszego numeru referencyjnego. Powinna ona umowę frexp trochę bardziej jasne:

/* 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

Myślałem, że pakiet Math Apache Commons może być dobrym miejscem do znalezienia tego, ale nic tam nie widziałem. Być może mógłbyś dodać do niego żądanie funkcji? Lub, jeśli zdecydujesz się sam to zakodować, porozmawiaj z nimi o włączeniu go do biblioteki - wydaje się przydatnym dodatkiem do mnie. – Carl

+0

@Carl, zgadzam się, że byłoby to przydatne. Bardzo dobrze znam siebie i moją pracę, więc nie zamierzam próbować tworzyć jej samodzielnie. Jestem pewien, że mogłem wykonać 80% pracy w 80% poprawnie z czasem, który muszę zainwestować i to jest bardzo bliskie niż bezużyteczne ... –

+0

prawdziwe pytanie brzmi: dlaczego frexp nie łamie float na dwie liczby całkowite, ale chce co najmniej float. Dla dekompozycji float, która nie ma sensu (myśl rekurencja .....) –

Odpowiedz

3

Jak to jest

.?
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; 
} 

To jest "inspirowane" lub właściwie prawie skopiowane identycznie z answer na podobne pytanie C#. Działa z bitami, a następnie czyni mantysę liczbą od 1,0 do 0,0.

+0

Yikes! Powyższy kod nie jest całkiem poprawny: powinien być podczas (realMant> = 1.0) zamiast while (realMant> 1.0). Wartość zwracanej wartości musi zawierać się w przedziale od 1/2 (włącznie) do 1 (wyłączne), patrz [podręcznik GNU libc] (http://www.gnu.org/software/libc/manual/html_node/Normalizacja -Functions.html). Z powyższym kodem, frexp (1.0) błędnie zwróci 1.0 zamiast 0.5. – akbertram

-1

Nie jestem zaznajomiony z funkcją frexp, ale myślę, że trzeba spojrzeć na "przeskalowane i nieskalowanych wartości BigDecimal. "nieskalowane" to precyzyjna mantysa, skala to wykładnik. W psuedocode: value = unscaledValue 10^(- scale)

1

Zobacz Float.floatToIntBits i Double.DoubleToLongBits. Nadal potrzebujesz trochę dodatkowej logiki, aby odszyfrować punkty zmienne IEEE 754.

+0

Dzięki - jestem świadomy możliwości dostania się do bitów. Nie chodzi mi o podstawowy argument parsowania s, e i m z zestawu bitów.Bardziej martwię się o kompletną implementację frexp, która utrzymuje kontrakt obsługi wszystkich narożnych przypadków (na przykład różne smaki NaN). –

0

To robi, co chcesz.

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, dzięki, ale frexp faktycznie działa z bitami standardu zmiennoprzecinkowego IEEE, zamiast próbować wywnioskować wynik matematyczny. Oto cel tego pytania. –

-1

Nope nie ma prądu w podstawowej implementacji Javy lub w Commons Lang (najprawdopodobniej inne miejsce, aby go znaleźć), który ma dokładnie taką samą funkcjonalność i łatwość frexp; o którym wiem. Jeśli istnieje, to prawdopodobnie w niezbyt powszechnie używanym pakiecie narzędzi.

0

Jeśli czytam tego prawa ...

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

Niestety, nie wydaje się być wbudowane w sposób, aby uzyskać mantysę bez konwertowania go do BigDecimal pierwszy (lub po prostu robi podział. result = param/Math.pow(2,n)

dziwo, scalb jest dokładnie odwrotnie: wziąć mantysy i wykładnika i wygenerować nowy pływak z niego

+0

@R. Bemrose, celem całego ćwiczenia nie jest nawrócenie. Zamiast tego funkcja przyjmuje standardową reprezentację zmiennoprzecinkową IEEE i dekoduje ją. Celem nie jest wymyślenie matematycznego wyrażenia, które wydaje się dawać taką samą odpowiedź. –

Powiązane problemy