2013-10-26 2 views
0

그래서 내가 BigDecimal의 값 0.99을 잡고 내가 호출이 :자바 : 동일한 부동 소수점 값에 대한 16 진수 값이 다른 이유는 무엇입니까?

  • Float.toHexString (rationalNumber.floatValue()) 내가 0x1.fae148p-1
  • Double.toHexString (rationalNumber.doubleValue를 얻을 수()) 내가 얻을 0x1.fae147ae147aep-1 우리는 우리가 관계없이 동일한 16 진수 값을 받아야 0.99 같은 작은 수를 나타내는 때문에 내가 생각하고

. 동의하다?

코드 (실패 시험) :

@Test public void testDelta() { 
    BigDecimal rationalNumber = new BigDecimal("0.99").setScale(2,BigDecimal.ROUND_DOWN); 

    String hexFromFloat = Float.toHexString(rationalNumber.floatValue()); 
    String hexFromDouble = Double.toHexString(rationalNumber.doubleValue()); 

    String hexFromFloatMsg = rationalNumber.floatValue() + " = " + hexFromFloat; 
    String hexFromDoubleMsg = rationalNumber.doubleValue() + " = " + hexFromDouble; 

    Assert.assertEquals(hexFromFloatMsg + ", " + hexFromDoubleMsg, hexFromDouble, hexFromFloat); 
} 

출력 :

org.junit.ComparisonFailure: 0.99 = 0x1.fae148p-1, 0.99 = 0x1.fae147ae147aep-1 
Expected :0x1.fae147ae147aep-1 
Actual :0x1.fae148p-1 
우리는 우리가 관계없이 동일한 16 진수 값을 받아야 0.99 같은 작은 수를 나타내는 때문에

답변

2

차이는 두 연산에서 발생

rationalNumber.floatValue() 
rationalNumber.doubleValue() 

이들 각각은 부동 소수점에 BigDecimal 0.99의 값을 변환한다. 16 진수 부동 소수점 (2의 거듭 제곱에 대한 소수점 지수가 있음)에서 .99는 0x1.fae147ae147ae147 ... p-1입니다. 이 값을 float으로 변환하면 유효 숫자 (분수 부분)의 24 비트 만 저장할 수 있습니다. 이는 그 숫자가 float 유형의 유효 숫자에 해당하기 때문입니다. (23 비트는 명시 적으로 저장되고 다른 하나는 인코딩의 다른 부분에서 암시 적으로 포함됩니다.) 따라서 변환은 .99의 정확한 값을 24 비트에 맞는 값으로 반올림해야합니다. 이것은 1.fae148p-1을 생산합니다. 1.fae147ae147ae147 ... 바이너리로 24 비트를 계산하면 반올림이 발생하는 곳을 알 수 있습니다. 여기에 처음 24 비트가 굵게 표시되어 있습니다 : 1.11111010111000010100011 110101110000101000111 ... p-1. 반올림 할 때, 우리는 제거 될 비트를보고, 그것들이 보관되는 가장 낮은 비트의 절반 이상 (첫 번째 비트는 1이고, 그 이상의 1 비트가 더 있음)을보고 반올림하기로 결정합니다. 따라서 반올림을하면 1.11111010111000010100100p-1이 생성됩니다. 16 진수로, 1.fae148p-1입니다.

.99를 double으로 변환하면 유효 숫자 53 비트를 저장할 수 있습니다. 그래서 그것은 다른 위치에서 반올림됩니다. 이것은 0x1.fae147ae147aep-1을 생성합니다.

두 값이 서로 다르다는 것을 직접 비교하면 서로 다릅니다. 부동 소수점 형식에서 16 진수 숫자로 변환하면 결과가 달라집니다.

+0

많은 감사의 말씀 Eric,이 질문 [http://stackoverflow.com/questions/19590878/java-double-in-place-of-float]을 읽고 제 편집을보고 제게 알려주십시오. 발견. 다시 많은 감사드립니다. – jakstack

-1

. 동의하다?

작은 정밀도이지만 십진수로 표시되지만 16 진수 표현은 (0x1.f(ae147)*) 반복됩니다. 정확히 표현되고 있지만 은 정확히으로 인쇄 할 수 없습니다.

+0

감사합니다. "10 진수의 작은 정밀도입니다." 왜 정확히 인쇄 할 수 없습니까? 또한 반복되는 방식을 볼 수 없지만 최대 0x1.fae14까지는 동일하지만 나머지는 다른 것을 볼 수 있습니다. – jakstack

+0

"십진법의 작은 정밀도"는 기본 -10의 표현이 두 자리의 정밀도 만 필요로하며 정확히 인쇄 될 수 있음을 의미합니다. 반복에 대해 말한 것은 16 진수 표현에서'ae147' 부분이 반복된다는 것입니다. 숫자는 실제로 '0x1'입니다.fae147ae147ae147ae147ae147ae147ae147ae147ae147ae147ae147ae147ae147 ...'. 그것은 단지 몇 자릿수로 인쇄되고 있습니다. – Kevin

관련 문제