Pregunta

¿Hay un equivalente de Java de la función C / C ++ llamada frexp ? Si usted no está familiarizado, frexp es definido por Wikipedia para "romper número de coma flotante abajo en mantisa y exponente ".

Busco una implementación con velocidad y precisión, pero yo preferiría tener la exactitud si sólo pudiera elegir uno.

Este es el ejemplo de código de la primera referencia. Se debe hacer el frexp contraen un poco más claro:

/* 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 */
¿Fue útil?

Solución

¿Cómo es esto?

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

Este es "inspirado" o en realidad casi copiada de forma idéntica a partir de un respuesta a una pregunta similar en C #. Se trabaja con los bits y luego hace la mantisa un número entre 1,0 y 0,0.

Otros consejos

Vea Float.floatToIntBits y Double.doubleToLongBits. Usted todavía necesita un poco de lógica adicional para decodificar IEEE 754 puntos flotantes.

Esto hace lo que quiere.

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 estoy leyendo esto ...

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

Por desgracia, no parece haber un método integrado para obtener la mantisa sin convertirlo a un BigDecimal primera (o simplemente no hacer la división:. result = param / Math.pow(2,n)

Por extraño que parezca, scalb hace exactamente lo contrario: tomar una mantisa y exponente y generar un nuevo flotador de ella

.

No estoy familiarizado con la función frexp, pero creo que hay que buscar en la noreferrer BigDecimal ' escalados y sin escala los valores. 'Sin escala' es la mantisa de precisión, la escala es el exponente. En psuedocode: valor = unscaledValue 10 ^ (- escala)

Pues no hay ninguna aplicación actual en el núcleo de Java o en el Commons Lang (muy probablemente otro lugar para encontrarlo) que tiene exactamente la misma funcionalidad y facilidad de frexp ; que yo sepa. Si existe probablemente en un conjunto de herramientas no se utiliza ampliamente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top