IT story

0.1을 여러 번 더해도 손실이없는 이유는 무엇입니까?

hot-time 2020. 6. 14. 10:02
반응형

0.1을 여러 번 더해도 손실이없는 이유는 무엇입니까?


나는 0.1십진수가 유한 이진수 ( 설명 )로 정확하게 표현 될 수 없다는 것을 알고 있으므로 double n = 0.1약간의 정밀도를 잃고 정확하게되지 않을 것 0.1입니다. 반면에는 0.5이므로 정확하게 표현할 수 있습니다 0.5 = 1/2 = 0.1b.

0.1 세 번 추가 하면 정확히 0.3다음 코드가 인쇄 되지는 않는다고 이해할 수 있습니다 false.

double sum = 0, d = 0.1;
for (int i = 0; i < 3; i++)
    sum += d;
System.out.println(sum == 0.3); // Prints false, OK

그러나 0.1 5 번 을 추가 하면 정확히 0.5어떻게됩니까? 다음 코드가 인쇄됩니다 true.

double sum = 0, d = 0.1;
for (int i = 0; i < 5; i++)
    sum += d;
System.out.println(sum == 0.5); // Prints true, WHY?

0.1정확하게 표현할 수 없다면 어떻게 5 번 더하면 정확히 0.5표현할 수 있습니까?


반올림 오류는 무작위가 아니며 구현 방식은 오류를 최소화하려고 시도합니다. 이는 때때로 오류가 표시되지 않거나 오류가 없음을 의미합니다.

예를 들어 0.1정확히되지 0.1new BigDecimal("0.1") < new BigDecimal(0.1)하지만 0.5정확히1.0/2

이 프로그램은 실제 가치를 보여줍니다.

BigDecimal _0_1 = new BigDecimal(0.1);
BigDecimal x = _0_1;
for(int i = 1; i <= 10; i ++) {
    System.out.println(i+" x 0.1 is "+x+", as double "+x.doubleValue());
    x = x.add(_0_1);
}

인쇄물

0.1000000000000000055511151231257827021181583404541015625, as double 0.1
0.2000000000000000111022302462515654042363166809082031250, as double 0.2
0.3000000000000000166533453693773481063544750213623046875, as double 0.30000000000000004
0.4000000000000000222044604925031308084726333618164062500, as double 0.4
0.5000000000000000277555756156289135105907917022705078125, as double 0.5
0.6000000000000000333066907387546962127089500427246093750, as double 0.6000000000000001
0.7000000000000000388578058618804789148271083831787109375, as double 0.7000000000000001
0.8000000000000000444089209850062616169452667236328125000, as double 0.8
0.9000000000000000499600361081320443190634250640869140625, as double 0.9
1.0000000000000000555111512312578270211815834045410156250, as double 1.0

참고 : 그것은 0.3약간 꺼져 있지만 0.4비트에 도달하면 53 비트 제한에 맞도록 비트를 아래로 이동해야하며 오류는 무시됩니다. 또, 에러에 대한 크립 위로 0.6하고 0.7있지만 위해 0.81.0오류가 폐기된다.

5 번 추가하면 오류가 누적되고 취소되지 않습니다.

오류가 발생하는 이유는 정밀도가 제한되어 있기 때문입니다. 즉, 53 비트. 즉, 숫자가 커질수록 더 많은 비트를 사용하므로 끝에서 비트를 삭제해야합니다. 이 경우 반올림이 발생하여 선호합니다.
더 작은 숫자 (예 : 0.1-0.0999=>)를 얻을 때 반대 효과를 얻을 수 있으며 1.0000000000000286E-4이전보다 더 많은 오류가 표시됩니다.

예를 들어 Java 6에서 Math.round (0.49999999999999994)가 1을 반환하는 이유는 무엇입니까? 이 경우 계산에서 비트 손실로 인해 답이 크게 달라집니다.


부동 소수점에서의 오버플로 금지 x + x + x는 실제 3 *로 정확하게 올림 된 (즉 가장 가까운) 부동 소수점 숫자 x이며, x + x + x + x정확히 4 * x이며, x + x + x + x + x5 *의 경우 올바르게 반올림 된 부동 소수점 근사값입니다 x.

에 대한 첫 번째 결과 는 정확한 x + x + x사실에서 비롯됩니다 x + x. x + x + x따라서 단 하나의 반올림 결과입니다.

두 번째 결과는 더 어렵습니다. 여기 에서 한 가지 시연이 설명 됩니다 (스티븐 캐논은의 마지막 세 자리에 대한 사례 분석을 통해 다른 증거를 제시합니다 x). 요약하면, 3 * x2 * 와 동일한 2 진법에x 있거나 4 *와 같은 2 진법에 있으며 x, 각각의 경우 세 번째 덧셈의 오류가 두 번째 덧셈의 오류를 취소한다고 추론 할 수 있습니다 ( 우리가 이미 말했듯이 첫 번째 추가는 정확합니다.)

세 번째 결과 인 " x + x + x + x + x올바르게 반올림 됨 " 첫 번째 결과 의 정확도와 동일한 방식으로 두 번째 결과에서 파생됩니다 x + x.


두 번째 결과는 왜 0.1 + 0.1 + 0.1 + 0.1정확히 부동 소수점 숫자인지를 설명합니다 0.4. 유리수 1/10과 4/10은 부동 소수점으로 변환 될 때 동일한 상대 오차로 동일한 방식으로 근사됩니다. 이 부동 소수점 숫자의 비율은 정확히 4입니다. 상기 제 1 및 제 결과 표시 0.1 + 0.1 + 0.1와는 0.1 + 0.1 + 0.1 + 0.1 + 0.1그 자체로, 그들은 단지 각각에 결과를 관련, 순 에러 분석에 의해 추정되는 것보다 더 적은 에러를 갖는 것으로 예상 될 수 있지만, 3 * 0.15 * 0.1근접하지만 반드시 일치하는 것으로 예상 될 수있는, 0.3그리고 0.5.

If you keep adding 0.1 after the fourth addition, you will finally observe rounding errors that make “0.1 added to itself n times” diverge from n * 0.1, and diverge even more from n/10. If you were to plot the values of “0.1 added to itself n times” as a function of n, you would observe lines of constant slope by binades (as soon as the result of the nth addition is destined to fall into a particular binade, the properties of the addition can be expected to be similar to previous additions that produced a result in the same binade). Within a same binade, the error will either grow or shrink. If you were to look at the sequence of the slopes from binade to binade, you would recognize the repeating digits of 0.1 in binary for a while. After that, absorption would start to take place and the curve would go flat.


Floating point systems do various magic including having a few extra bits of precision for rounding. Thus the very small error due to the inexact representation of 0.1 ends up getting rounded off to 0.5.

Think of floating point as being a great but INEXACT way to represent numbers. Not all possible numbers are easily represented in a computer. Irrational numbers like PI. Or like SQRT(2). (Symbolic math systems can represent them, but I did say "easily".)

The floating point value may be extremely close, but not exact. It may be so close that you could navigate to Pluto and be off by millimeters. But still not exact in a mathematical sense.

Don't use floating point when you need to be exact rather than approximate. For example, accounting applications want to keep exact track of a certain number of pennies in an account. Integers are good for that because they are exact. The primary issue you need to watch for with integers is overflow.

Using BigDecimal for currency works well because the underlying representation is an integer, albeit a big one.

Recognizing that floating point numbers are inexact, they still have a great many uses. Coordinate systems for navigation or coordinates in graphics systems. Astronomical values. Scientific values. (You probably cannot know the exact mass of a baseball to within a mass of an electron anyway, so inexactness doesn't really matter.)

For counting applications (including accounting) use integer. For counting the number of people that pass through a gate, use int or long.

참고URL : https://stackoverflow.com/questions/26120311/why-does-adding-0-1-multiple-times-remain-lossless

반응형