Frage

Gibt es einen Java-Äquivalent von dem C / C ++ Funktion namens frexp ? Wenn Sie nicht vertraut sind, frexp ist definiert durch Wikipedia „break Gleitkommazahl nach unten in Mantisse und Exponenten. "

Ich bin für eine Implementierung mit Geschwindigkeit und Genauigkeit, aber ich würde eher die Genauigkeit, wenn ich nur eine wählen kann.

Dies ist das Codebeispiel von der ersten Referenz. Es sollte den frexp Vertrag ein wenig mehr klar machen:

/* 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 */
War es hilfreich?

Lösung

Wie ist das?

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

Dies wird als „inspiriert“ oder eigentlich fast identisch von einem Antwort auf eine ähnliche C # Frage. Es arbeitet mit den Bits und dann macht die Mantisse eine Zahl zwischen 1,0 und 0,0.

Andere Tipps

Siehe Float.floatToIntBits und Double.doubleToLongBits. Sie müssen noch ein wenig zusätzliche Logik zu dekodieren IEEE 754 Floating Punkte.

Das tut, was Sie wollen.

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

Wenn ich das richtig gerade lese ...

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

Leider ist es nicht angezeigt, eine integrierte Methode, um die Mantisse zu bekommen, ohne es zu einem BigDecimal Umwandeln einer ersten (oder tun Sie einfach die Teilung. result = param / Math.pow(2,n)

Merkwürdigerweise scalb tut genau das Gegenteil. Nehmen eine Mantisse und Exponent und erzeugen einen neuen Schwimmer aus it

Ich bin mit der frexp Funktion nicht vertraut, aber ich glaube, Sie bei der BigDecimal ‘ skaliert und nicht skalierte Werte. ‚Unscaled‘ ist die Präzision Mantisse, Maßstab ist der Exponent. In psuedocode: value = unscaledValue 10 ^ (- Skala)

Nein gibt es keine aktuelle Implementierung in Java-Kern oder in dem Commons Lang (höchstwahrscheinlich anderen Ort, um es zu finden), die genau die gleiche Funktionalität und Leichtigkeit von frexp ; die ich kenne. Wenn es existiert, es ist wahrscheinlich in einem nicht weit verbreitetes Toolkit.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top