예를 들어, 달러를 사용하면 $ 0.01 미만의 정밀도를 갖지 못합니다
아 진짜?
IEEE 754 부동 소수점 숫자로 통화를 저장해서는 안되는 오래된 문제.
인치를 IEEE 754 부동 소수점 숫자로 자유롭게 저장하십시오 . 그들은 당신이 기대하는 방식을 정확하게 저장합니다.
눈금자를 1 인치 단위로 나누는 눈금을 사용하여 저장할 수있는 금액을 IEEE 754 부동 소수점 숫자로 자유롭게 저장하십시오 .
왜? IEEE 754 를 사용할 때 저장하는 방식입니다.
인치에 관한 것은 반으로 나뉘어져 있다는 것입니다. 대부분의 종류의 통화는 10 분의 1로 나뉩니다 (일부 종류는 아니지만 초점을 유지합시다).
이 차이는 대부분의 프로그래밍 언어의 경우 IEEE 754 부동 소수점 숫자의 입력 및 출력 이 10 진수로 표현 된다는 점을 제외하고는 혼란스럽지 않습니다 ! 십진수로 저장되지 않기 때문에 매우 이상합니다.
이 때문에 컴퓨터에 저장을 요청할 때 비트가 어떻게 이상한 일을하는지 알 수 없습니다 0.1
. 수학을 할 때 이상한 점만 보이고 이상한 오류가 있습니다.
에서 조쉬 블로흐의 효과적인 자바 :
System.out.println(1.03 - .42);
생산 0.6100000000000001
이것에 대해 가장 잘 말하는 1
것은 오른쪽에 앉아있는 것이 아닙니다 . 그것을 얻기 위해 사용해야했던 이상한 숫자입니다. 가장 인기있는 예를 사용하기보다는 0.1
문제를 보여주고 문제를 숨기는 반올림을 피하는 예를 사용해야합니다.
예를 들어 왜 이것이 작동합니까?
System.out.println(.01 - .02);
생산 -0.01
우리가 운이 좋았 기 때문에.
나는 때때로 "운"을 얻기 때문에 진단하기 어려운 문제가 싫어.
IEEE 754는 단순히 0.1을 정확하게 저장할 수 없습니다. 그러나 0.1을 저장하고 인쇄하도록 요청하면 0.1이 표시되고 모든 것이 잘된다고 생각합니다. 괜찮지는 않지만 0.1로 돌아 가기 위해 반올림하기 때문에 볼 수 없습니다.
어떤 사람들은 이러한 불일치 반올림 오류를 불러서 다른 사람들과 혼동을 일으 킵니다. 아니요, 반올림 오류가 아닙니다. 반올림은 예정된 작업을 수행하고 소수가 아닌 것을 소수점으로 바꾸어 화면에 인쇄 할 수 있습니다.
그러나 이것은 숫자 표시 방법과 저장 방법 사이의 불일치를 숨 깁니다. 반올림이 발생했을 때 오류가 발생하지 않았습니다. 정확하게 저장할 수없는 시스템에 숫자를 입력하기로 결정하고 그렇지 않은 경우 정확하게 저장되었다고 가정했을 때 발생했습니다.
아무도 π가 계산기에 정확하게 저장 될 것으로 기대하지 않으며 제대로 작동 할 수 있습니다. 따라서 문제는 정밀도조차도 아닙니다. 예상 정밀도에 관한 것입니다. 컴퓨터는 0.1
계산기와 마찬가지로 10 분의 1을 표시 하므로 계산기와 10 분의 1을 완벽하게 저장해야합니다. 그들은하지 않습니다. 컴퓨터가 더 비싸기 때문에 놀랍습니다.
불일치를 보여 드리겠습니다.
1/2과 0.5가 완벽하게 정렬됩니다. 그러나 0.1은 정렬되지 않습니다. 2를 계속 나누면 더 가까이 다가 갈 수 있지만 정확하게 맞지는 않을 것입니다. 우리는 2로 나눌 때마다 점점 더 많은 비트가 필요합니다. 따라서 2로 나누는 모든 시스템에서 0.1을 나타내려면 무한한 수의 비트가 필요합니다. 내 하드 드라이브는 그렇게 크지 않습니다.
따라서 IEEE 754 는 비트가 부족할 때 시도를 중지합니다. 가족 사진을 보관할 하드 디스크 공간이 필요해서 좋네요. 아니야 가족 사진. :피
어쨌든, 당신이 입력 한 것과 당신이 보는 것은 소수점 (오른쪽)이지만 당신이 저장하는 것은 이진수 (왼쪽)입니다. 때로는 그것들이 완전히 동일합니다. 때로는 그렇지 않습니다. 때로는 단순히 그렇지 않을 때도 같은 것처럼 보입니다. 반올림입니다.
특히, 일부 통화로 값을 저장하고 인쇄하려면 무엇을 알아야합니까?
10 진수 기반의 돈을 처리하는 경우 float 또는 double을 사용하지 마십시오.
10 분의 1 페니와 같은 일이 관여하지 않을 것이라고 확신한다면 페니를 보관하십시오. 그렇지 않으면이 통화의 가장 작은 단위가 무엇인지 알아 내고 사용하십시오. 할 수 없다면 BigDecimal 과 같은 것을 사용하십시오 .
내 순 가치는 아마도 64 비트 정수에 항상 적합하지만 BigInteger 와 같은 것은 그보다 큰 프로젝트에서 잘 작동합니다. 그들은 기본 유형보다 느립니다.
그것을 저장하는 방법을 알아내는 것은 문제의 절반에 불과합니다. 또한 표시 할 수 있어야합니다. 좋은 디자인은이 두 가지를 분리합니다. 여기서 float를 사용할 때의 실제 문제는 두 가지가 함께 숨겨져 있다는 것입니다.