【问题标题】:How to convert a double to its exact fractional equivalent in Java?如何在 Java 中将双精度数转换为其精确的小数等价物?
【发布时间】:2015-01-31 06:35:34
【问题描述】:

从技术角度来说,我需要一种方法,将 IEEE 754 binary64 number 转换为两个 BigInteger 的缩减比率,这两个 BigInteger 在数学上表示完全相同的值。该方法不需要处理infiniteNaN 的值,但它确实需要处理subnormalssigned zeros。由于 IEEE 754 binary64 数字格式不支持表示无理数,所以这个任务理论上是可以的。

以下是一些示例值:

  • 0.0 = 0 / 1
  • -0.0 = 0 / 1
  • 0.5 = 1 / 2
  • 0.1 = 3602879701896397 / 36028797018963968
  • 1 /(双)3 = 6004799503160661 / 18014398509481984
  • Double.MIN_NORMAL = 1/2 ^ 1022 = 1/44942328371557897693232629769725618340449424473557664318357520289433168951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034304 LI>
  • Double.MIN_VALUE = 1/2 ^ 1074 = 1/202402253307310618352495346718917307049556649764142118356901358027430339567995346891960383701437124495187077864316811911389808737385793476867013399940738509921517424276566361364466907742093216341239767678472745068562007483424692698618103355649159556340810056512358769552333414615230502532186327508646006263307707741093494784 LI>
  • Double.MAX_VALUE =(2 ^ 1024 - 2 ^ 971)/ 1 = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368/1 LI>

【问题讨论】:

    标签: java function math methods


    【解决方案1】:

    这种方法检查双精度位以防止舍入错误。

    在双精度中,第一位是符号,接下来的 11 位是指数,最后 52 位是有效数。

    我发现将整个值与 0 进行比较更容易,而不是检查第一位。

    我没有获取指数的位并处理指数的符号(与值的符号不同),而是使用Math.getExponent 来获取它的有符号值。根据其documentation

    • 如果参数为 NaN 或无穷大,则结果为 Double.MAX_EXPONENT + 1。
    • 如果参数为零或低于正常值,则结果为 Double.MIN_EXPONENT -1。

    如果该值不是次正规的,则有效数字在其 52 位之前有一个隐含的前导 1。指数假设二进制点(即小数点)在前导 1 之后,所以我从指数中减去 52 以将二进制点移到末尾。

    public static BigInteger[] convertToFraction(double value) {
      int exponent = Math.getExponent(value);
      if (exponent > Double.MAX_EXPONENT) {
        // The value is infinite or NaN.
        throw new IllegalArgumentException("Illegal parameter 'value': " + value);
      }
      long positiveSignificand;
      if (exponent < Double.MIN_EXPONENT) {
        // The value is subnormal.
        exponent++;
        positiveSignificand = Double.doubleToLongBits(value) & 0x000fffffffffffffL;
      } else {
        positiveSignificand = (Double.doubleToLongBits(value) & 0x000fffffffffffffL) | 0x0010000000000000L;
      }
      BigInteger significand = BigInteger.valueOf(value < 0 ? -positiveSignificand : positiveSignificand);
      exponent -= 52; // Adjust the exponent for an integral significand.
      BigInteger coefficient = BigInteger.ONE.shiftLeft(Math.abs(exponent));
      if (exponent >= 0) {
        return new BigInteger[] { significand.multiply(coefficient), BigInteger.ONE };
      } else {
        BigInteger gcd = significand.gcd(coefficient);
        return new BigInteger[] { significand.divide(gcd), coefficient.divide(gcd) };
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-14
      • 1970-01-01
      • 1970-01-01
      • 2015-09-13
      • 1970-01-01
      • 1970-01-01
      • 2011-07-07
      • 1970-01-01
      相关资源
      最近更新 更多