سؤال

هل هناك ما يعادل Java من وظيفة C / C ++ المسمى Frexp؟ إذا لم تكن مألوفًا ، فهو FREXP حددها ويكيبيديا إلى "كسر رقم النقطة لأسفل إلى Mantissa و Provonent."

أنا أبحث عن تنفيذ مع كل من السرعة والدقة ، لكنني أفضل أن أحصل على الدقة إذا كان بإمكاني اختيار واحدة فقط.

هذه هي عينة الكود من المرجع الأول. يجب أن يجعل عقد 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 */
هل كانت مفيدة؟

المحلول

كيف هذا؟

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

هذا "مستوحى" أو تم نسخه بشكل متطابق تقريبًا من إجابه إلى سؤال مماثل C#. إنه يعمل مع البتات ثم يجعل Mantissa رقم بين 1.0 و 0.0.

نصائح أخرى

انظر float.floattointbits و double.doubletolongbits. لا تزال بحاجة إلى القليل من المنطق الإضافي لفك تشفير IEEE 754 نقطة عائمة.

هذا يفعل ما تريد.

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

إذا كنت أقرأ هذا بشكل صحيح ...

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

لسوء الحظ ، لا يبدو أن هناك طريقة مدمجة للحصول على Mantissa دون تحويلها إلى BigDecimal أولاً (أو مجرد القيام بالقسمة: result = param / Math.pow(2,n).

غريب كفاية، scalb هل العكس تمامًا: خذ mantissa وأسعد وتوليد تعويم جديد منه.

لست على دراية بوظيفة FREXP ، لكنني أعتقد أنك بحاجة إلى النظر إلى BigDecimal'القيم المقيدة وغير المنقوقة. "Uncaled" هو mantissa الدقة ، المقياس هو الأسس. في psuedocode: القيمة = UncaledValue 10^(-المقياس)

لا ، لا يوجد تنفيذ حالي في جافا الأساسية أو في مجلس العموم (على الأرجح مكان آخر للعثور عليه) له نفس الوظائف وسهولة الدقة Frexp; ؛ التي أعرفها. إذا كانت موجودة ، فربما تكون في مجموعة أدوات غير مستخدمة على نطاق واسع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top