2014-12-02 47 views
4

從技術角度而言,我需要一種將IEEE 754 binary64 number轉換爲兩個BigInteger的縮減比率的方法,它們在數學上表示完全相同的值。該方法不需要處理值爲infiniteNaN,但它確實需要處理subnormalssigned zeros。由於IEEE 754 binary64數字格式不支持表示無理數,因此這項任務在理論上是可行的。如何將double轉換爲Java中精確的小數部分?

下面是一些示例值:

  • 0.0 = 0/1
  • -0.0 = 0/1
  • 0.5 = 1/
  • 0.1 =36028797018963968分之3602879701896397
  • 1/(double)3 = 6004799503160661/18014398509481984
  • Double.MIN_NORMAL = 1/2^1022 = 1/44942328371557897693232629769725618340449424473557664318357520289433168 951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034304
  • Double.MIN_VALUE = 1/2^1074 = 1/202402253307310618352495346718917307049556649764142118356901358027430339567995346891960383701437124495187077864316811911389808737385793476867013399940738509921517424276566361364466907742093216341239767678472745068562007483424692698618103355649159556340810056512358769552333414615230502532186327508646006263307707741093494784
  • Double.MAX_VALUE =(2^1024 - 2^971)/ 1 = 17976931348623157081452742373170435679807056752584499659891747680315726078002853876058955863276687817154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932 8944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368/1

回答

4

這種方法檢查double的位來防止舍入誤差。

在一個double中,第一位是符號,下一個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) }; 
    } 
} 
相關問題