서문: 직장에서 소수점을 사용한 덧셈, 뺄셈, 곱셈, 나눗셈을 할 때 BigDecimal을 사용하여 해결하려고 생각하지만 많은 사람들이 double 또는 float가 정밀도를 잃는 이유에 대해 혼란스러워합니다. BigDecimal을 해결하는 방법은 무엇입니까? 더 이상 고민하지 말고 시작해 보겠습니다.
1. 부동소수점 숫자란 무엇인가요?
부동 소수점 숫자는 과학적 표기법을 사용하여 소수를 표현하기 위해 컴퓨터에서 사용하는 데이터 유형입니다. Java에서 double은 배정밀도, 64비트 부동 소수점 숫자이며 기본값은 0.0d입니다. float는 단정밀도, 32비트 부동 소수점 숫자이며 기본값은 0.0f입니다.
메모리에 저장됨
float 부호 비트(1비트) 지수(8비트) 가수(23비트)
이중 부호 비트( 1bit) 지수(11비트) 가수(52비트)
float는 메모리에 8비트의 지수를 가지고 있으므로 지수의 실제 값을 e라고 가정하면 지수 코드는 실제로 지수의 프레임 코드를 저장합니다. 지수 코드는 E이면 E= e+(2^n-1 -1)입니다. 그 중 2^n-1 -1은 IEEE754 표준에서 지정한 지수 오프셋이다. 이 공식에 따르면 2^8 -1=127을 얻을 수 있다. 따라서 float의 지수 범위는 -128 +127이고, double의 지수 범위는 -1024 +1023입니다. 음수 지수는 부동 소수점 숫자가 표현할 수 있는 절대값이 가장 작은 0이 아닌 숫자를 결정하고, 양수 지수는 부동 소수점 숫자가 표현할 수 있는 절대값이 가장 큰 숫자를 결정합니다. 부동 소수점 숫자의 값 범위.
float의 범위는 -2^128 ~ +2^127이며, 이는 -3.40E+38 ~ +3.40E+38입니다.
double의 범위는 -2^1024 ~ +2^1023입니다. -1.79 E+308 ~ +1.79E+308
2. 왜곡의 과학적 표기법에 대해 알아보세요
먼저 과학적 표기법에 대해 이야기해보겠습니다. 자릿수가 많은 숫자, 과학적 표기법은 자릿수가 작은 값에는 장점이 없지만 자릿수가 많은 값의 경우 계산 방법의 장점은 매우 분명합니다. 예를 들어, 빛의 속도는 300000000미터/초이고, 세계 인구는 약 6억100000000명입니다. 빛의 속도와 세계 인구와 같은 큰 숫자는 읽고 쓰기가 매우 불편하므로 빛의 속도는 3*10^8, 세계 인구는 6.1*10^9로 쓸 수 있습니다. 그래서 계산기는 과학적 표기법을 사용하여 빛의 속도가 3E8이고 세계 인구는 약 6.1E9임을 나타냅니다.
어렸을 때 우리는 계산기를 가지고 미친 듯이 덧셈과 뺄셈을 하곤 했습니다. 결국 계산기에는 아래 그림이 표시됩니다. 과학적 표기법으로 표시한 결과입니다
그림의 실제 값은 -4.86*10^11=-486000000000입니다. 소수 과학 표기법에서는 유효 숫자의 정수 부분이 간격 [1, 9] 내에 있어야 합니다.
3. 왜곡의 정확성 알아보기
데이터의 컴퓨터 처리에는 데이터 변환과 다양한 단위 변환, 다양한 진수 변환(예: 이진수 10진수) 등과 같은 다양한 복잡한 작업이 포함됩니다. 예를 들어 10¼3=3.3333...은 끝이 없지만 정확도에는 제한이 있습니다. 3.3333333x3은 10이 아닙니다. 복잡한 처리를 거쳐 얻은 십진수 데이터는 정확도가 높을수록 정확하지 않습니다. 이다. float 및 double의 정확도는 가수의 자릿수에 따라 결정됩니다. 정수 부분은 변경되지 않으므로 항상 암시적 "1"입니다. float: 2^23 = 8388608, 총 7자리입니다. 가장 왼쪽 숫자가 생략되었기 때문에 최대 8자리까지 표현할 수 있다는 뜻입니다: 28388608 = 16777216. 유효 숫자는 8개이지만 절대적으로 7자리가 보장됩니다. 즉, float의 정밀도는 7~8개의 유효 숫자입니다. double: 2^52 = 4503599627370496, 총 16자리, 마찬가지로 double의 정밀도도 마찬가지입니다. 16~17비트입니다.
특정 값에 도달하면 자동으로 과학적 표기법을 사용하기 시작하고 관련 정밀도의 유효 숫자를 유지하므로 결과는 대략적인 숫자이고 지수는 정수입니다. 십진법에서는 일부 소수를 이진법으로 완전히 표현할 수 없습니다. 따라서 제한된 비트로만 표현할 수 있어 저장 시 오류가 발생할 수 있습니다. 십진수를 이진수로 변환하려면 2 곱셈 방법을 사용하여 정수 부분을 제거한 후 소수 부분이 모두 0이 될 때까지 나머지 소수에 2를 계속 곱합니다.
이 0.19999999999999998
인 상황이 발생하면 0.3-0.1을 입력하세요. 연산을 위해서는 0.3을 바이너리로 변환해야 합니다
0.3 * 2 = 0.6 => .0(.6)은 0을 취하고 0.6
0.6 * 2 = 1.2 => .01(.2)은 1을 취하고 0.2를 남깁니다.
0.2 * 2 = 0.4 => .010(.4)은 0을 취하고 0.4
0.4 * 2 = 0.8 => .0100(.8)은 0을 취하고 0.8
0.8 * 2 => 01001 (.6 )은 1을 취하고 0.6을 남깁니다
..............
3. 요약
위 내용을 읽고 나면 부동 소수점 숫자가 왜 정확성을 갖는지 분명해질 것입니다. 문제. 간단히 말해서, float 및 double 유형은 주로 과학적 계산 및 공학적 계산을 위해 설계되었습니다. 이 유형은 광범위한 값에 대해 보다 정확하고 빠른 근사 합계 계산을 제공하도록 신중하게 설계된 이진 부동 소수점 연산을 수행합니다. 그러나 완전히 정확한 결과를 제공하지는 않으며 정확한 결과를 위해 사용해서는 안 됩니다. 특정 크기에 도달하는 부동 소수점 숫자는 자동으로 과학적 표기법을 사용합니다. 이러한 표현은 실수의 근사치일 뿐 실수와 동일하지 않습니다. 10진수를 2진수로 변환하면 무한루프가 발생하거나 부동소수점 가수의 길이를 초과하게 됩니다.
4 그렇다면 BigDecimal을 사용하여 어떻게 해결할 수 있을까요?
아래 두 출력을 보세요
출력 결과
0.2999999999999998889 7 769753748434595763683319091796875#🎜🎜 #0.3
위 내용은 이중 부동 소수점 연산이 정밀도를 잃는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!