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.1
즉 new 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.8
에 1.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 + x
5 *의 경우 올바르게 반올림 된 부동 소수점 근사값입니다 x
.
에 대한 첫 번째 결과 는 정확한 x + x + x
사실에서 비롯됩니다 x + x
. x + x + x
따라서 단 하나의 반올림 결과입니다.
두 번째 결과는 더 어렵습니다. 여기 에서 한 가지 시연이 설명 됩니다 (스티븐 캐논은의 마지막 세 자리에 대한 사례 분석을 통해 다른 증거를 제시합니다 x
). 요약하면, 3 * x
는 2 * 와 동일한 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.1
및 5 * 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
'IT story' 카테고리의 다른 글
#defining WIN32_LEAN_AND_MEAN에서 정확히 제외하는 것은 무엇입니까? (0) | 2020.06.15 |
---|---|
혼합 콘텐츠를 허용하도록 Chrome을 사용하는 방법은 무엇입니까? (0) | 2020.06.15 |
왜 C # 컴파일러가이 비교를 마치> 비교 인 것처럼 해석합니까? (0) | 2020.06.14 |
3 개의 다른 평등 (0) | 2020.06.14 |
사전 뷰 객체 란 무엇입니까? (0) | 2020.06.14 |