2014-12-02 3 views
4

기술적 인면에서 IEEE 754 binary64 number을 수학적으로 정확하게 동일한 값을 나타내는 두 개의 BigInteger 비율로 변환하는 방법이 필요합니다. 이 메서드는 infinite 또는 NaN 값을 처리 할 필요는 없지만 subnormalssigned zeros을 처리해야합니다. IEEE 754 binary64 number 형식은 비합리적인 숫자를 나타내는 것을 지원하지 않으므로 이론적으로이 작업이 가능합니다. 여기 이중을 Java에서 정확한 분수로 변환하는 방법은 무엇입니까?

일부 예로 값이다 :

  • 0.0 = 0/1
  • -0.0 = 0/1
  • = 0.5 2분의 1
  • 0.1 = 36,028,797,018,963,968분의 3,602,879,701,896,397
  • 1/(이중) 3 = 6004799503160661/18014398509481984
  • Double.MIN_NORMAL = 1/2^1022 = 1/44942328371557897693232629769725618340449424473557664318357520289433168 951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034304
  • Double.MIN_VALUE가 = 1/2^1,074 = 1/202402253307310618352495346718917307049556649764142118356901358027430339567995346891960383701437124495187077864316811911389808737385793476867013399940738509921517424276566361364466907742093216341239767678472745068562007483424692698618103355649159556340810056512358769552333414615230502532186327508646006263307707741093494784
  • 만들어 Double.MAX_VALUE = (1,024 ^은 2 - 2로^971)/1 = 17976931348623157081452742373170435679807056752584499659891747680315726078002853876058955863276687817154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932 8944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368/1

답변

4

이 방법은 반올림 오류를 방지하기 위해 이중의 비트를 검사합니다.

이중에서는 첫 번째 비트가 부호이고 다음 11 개는 지수이며 마지막 52 개는 유효 숫자입니다.

대신 첫 번째 비트를 확인, 나는 쉽게 단지 대신 값의 기호와 구별되는 (지수의 비트를 얻고 지수의 기호를 다루는 0

에 전체 값을 비교 발견), 나는 Math.getExponent을 사용하여 서명 된 값을 얻습니다. 인수는 0 또는 비정규는, 결과가 Double.MIN_EXPONENT 인 경우 그 documentation,

  • 인수가 NaN 또는 무한대의 경우에있어서, 결과는 Double.MAX_EXPONENT + 1
  • 인 - 1.

값 비정규 없다면, 유효 숫자를 갖는 52 비트의 내재적 전에 한 선도. 지수는 이진수 포인트 (즉, 소수점)가 선행 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) }; 
    } 
} 
관련 문제