>일반적인 문제 >이중 부동 소수점 연산이 정밀도를 잃는 이유는 무엇입니까?

이중 부동 소수점 연산이 정밀도를 잃는 이유는 무엇입니까?

步履不停
步履不停원래의
2019-06-26 09:15:404644검색

이중 부동 소수점 연산이 정밀도를 잃는 이유는 무엇입니까?

서문: 직장에서 소수점을 사용한 덧셈, 뺄셈, 곱셈, 나눗셈을 할 때 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

사진 속 알리바바의 코드 제약 플러그인은 경고를 표시하고 BigDecimal을 생성하려면 문자열 매개변수의 생성 방법을 사용하라고 요청했습니다. double은 정확히 0.3(유한 길이의 이진수)으로 표현될 수 없기 때문에 생성자가 전달한 값은 정확히 0.3과 같지 않습니다. BigDecimal을 사용하는 경우 String 매개변수의 생성자 메서드를 사용하여 생성해야 합니다. 그런데 궁금한 아기들이 있는데 BigDecimal의 원리는 무엇인가요? 왜 문제가 없나요? 실제로 원리는 매우 간단합니다. BigDecimal은 불변이며 모든 정밀도의 부호 있는 십진수를 나타내는 데 사용할 수 있습니다. double의 문제는 소수점이 이진수로 변환되어 정밀도가 손실되기 때문입니다. 처리 중에 BigDecimal은 정수로 계산할 수 있고 해당 정밀도 정보를 유지할 수 있도록 십진수를 N배로 확장합니다. BigDecimal이 어떻게 저장되는지는 소스 코드를 읽을 수 있습니다.

자주 묻는 질문(FAQ)과 관련된 기술 관련 기사를 더 보려면

FAQ 열을 방문하여 자세히 알아보세요!

위 내용은 이중 부동 소수점 연산이 정밀도를 잃는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.