Question

Y at-il un équivalent Java de la fonction C / C ++ appelé frexp ? Si vous n'êtes pas familier, frexp est défini par Wikipedia pour « pause nombre à virgule flottante vers le bas dans mantisse et exposant. "

Je cherche une mise en œuvre à la fois la vitesse et la précision, mais je préférerais avoir la précision si je ne pouvais choisir un.

Ceci est l'exemple de code de la première référence. Il devrait faire le frexp contracter un peu plus clair:

/* 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 */
Était-ce utile?

La solution

Comment ce?

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

est « inspiré » ou en fait presque copié à l'identique d'un réponse à une question similaire C #. Il fonctionne avec les bits et fait alors la mantisse un nombre compris entre 1,0 et 0,0.

Autres conseils

Voir Float.floatToIntBits et Double.doubleToLongBits. Vous avez encore besoin d'un peu de logique supplémentaire pour décoder IEEE 754 points flottants.

Cela ne fait ce que vous voulez.

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

Si je lis ce droit ...

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

Malheureusement, il ne semble pas être une méthode intégrée pour obtenir la mantisse sans le convertir à un BigDecimal premier (ou juste faire la division. result = param / Math.pow(2,n)

Etrangement, scalb fait exactement le contraire: prendre une mantisse et exposant et générer un nouveau flotteur de celui-ci

.

Je ne suis pas au courant de la fonction frexp, mais je pense que vous devez regarder le « valeurs mises à l'échelle et unscale BigDecimal. « Unscaled » est la mantisse de précision, l'échelle est l'exposant. Dans psuedocode: value = unscaledValue 10 ^ (- échelle)

Non il n'y a pas d'implémentation actuelle dans le noyau Java ou dans les communes Lang (autre endroit le plus susceptible de le trouver) qui a la même fonctionnalité et la facilité exacte de frexp ; que je connais. Si elle existe, il est probablement dans une boîte à outils pas largement utilisé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top