부동 소수점 연산에 문제가 있나요?
P粉330232096
P粉330232096 2023-08-21 15:24:30
0
2
525
<p>다음 코드를 고려해보세요: </p> <pre class="brush:js;toolbar:false;">0.1 + 0.2 == 0.3 -> </pre> <pre class="brush:js;toolbar:false;">0.1 + 0.2 -> 0.30000000000000004 </pre> <p>왜 이러한 부정확성이 발생합니까? </p>
P粉330232096
P粉330232096

모든 응답(2)
P粉041856955

하드웨어 디자이너의 관점

저는 부동 소수점 하드웨어를 설계하고 구축하기 때문에 하드웨어 디자이너의 관점에서 몇 가지 관점을 추가해야 한다고 생각했습니다. 오류의 원인을 알면 소프트웨어에서 무슨 일이 일어나고 있는지 이해하는 데 도움이 될 수 있으며, 궁극적으로 부동 소수점 오류가 발생하고 시간이 지남에 따라 누적되는 것처럼 보이는 이유를 설명하는 데 도움이 되기를 바랍니다.

1. 개요

엔지니어링 관점에서 볼 때, 부동 소수점 계산을 수행하는 하드웨어는 마지막 비트의 절반 미만에서 1단위 오류만 있으면 되기 때문에 대부분의 부동 소수점 연산에는 약간의 오류가 있습니다. 따라서 대부분의 하드웨어는 단일 작업에서 마지막 비트 오류의 절반 미만만 생성하면 되는 정밀도에서 중지됩니다. 이는 특히 부동 소수점 나누기에서 까다롭습니다. 단일 연산을 구성하는 것은 장치에서 허용하는 피연산자 수에 따라 다릅니다. 대부분의 단위에서는 2개이지만 일부 단위에서는 3개 이상의 피연산자를 허용합니다. 따라서 반복된 작업으로 인해 이상적인 오류가 발생한다는 보장은 없습니다. 이러한 오류는 시간이 지남에 따라 누적되기 때문입니다.

2. 표준

대부분의 프로세서는 IEEE-754 표준을 따르지만 일부는 비정규화되거나 다른 표준을 사용합니다. 예를 들어, IEEE-754에는 정밀도를 희생하면서 매우 작은 부동 소수점 숫자를 표현할 수 있는 비정규화 모드가 있습니다. 다만, 다음은 일반적인 동작 모드인 IEEE-754의 정규화 모드에 대해 설명한다.

IEEE-754 표준에서 하드웨어 설계자는 마지막 비트 단위의 절반 미만인 오류/엡실론 값을 선택할 수 있으며 결과는 마지막 비트 단위의 절반 미만이면 됩니다. 작업. 이는 반복된 작업으로 인해 오류가 누적되는 이유를 설명합니다. IEEE-754 배정밀도의 경우 가수(예: 5.3e5의 5.3)라고도 하는 부동 소수점 숫자의 숫자 부분(정규화된 부분)을 나타내는 데 53비트가 사용되므로 이는 비트 54입니다. 다음 몇 섹션에서는 다양한 부동 소수점 연산에서 하드웨어 오류의 원인을 자세히 살펴보겠습니다.

3. 나눗셈 및 반올림 오류의 원인

부동소수점 나눗셈에서 오류가 발생하는 주요 원인은 몫을 계산하는 데 사용되는 나눗셈 알고리즘입니다. 대부분의 컴퓨터 시스템은 곱셈의 역을 사용하여 주로 Z=X/YZ = X * (1/Y)中。除法是迭代计算的,即每个周期计算一些商的位数,直到达到所需的精度,对于IEEE-754来说,这是任何误差小于最后一位的一半以下的内容。Y的倒数表(1/Y)称为慢除法中的商选择表(QST),商选择表的位数通常是基数的宽度,或者每次迭代计算的商的位数加上几个保护位。对于IEEE-754标准的双精度(64位),它将是除法器的基数大小加上几个保护位k,其中k>=2。因此,例如,一个每次计算2位商(基数为4)的典型商选择表将是2+2= 4 비트(몇 가지 선택적 비트 포함)에서 나눗셈을 계산합니다.

3.1 나눗셈 반올림 오류: 역수의 근사

몫 선택 테이블의 역수는 분할 방법에 따라 다릅니다. 느린 나누기(예: SRT 나누기) 또는 빠른 나누기(예: Goldschmidt 나누기) 각 항목은 오류를 최소화하기 위해 나누기 알고리즘에 따라 수정됩니다. 그럼에도 불구하고 모든 역수는 실제 역수의 근사치이며 어느 정도의 오류가 발생합니다. 느린 나눗셈과 빠른 나눗셈 방법 모두 반복적으로 몫을 계산합니다. 즉, 각 단계는 특정 수의 몫 자릿수를 계산한 다음 피제수에서 결과를 빼고, 제수는 오류가 마지막 자릿수의 절반 미만이 될 때까지 이러한 단계를 반복합니다. 숫자. 느린 나눗셈 방법은 각 단계에서 고정된 수의 몫 자릿수를 계산하고 일반적으로 비용이 저렴한 반면, 빠른 나눗셈 방법은 각 단계에서 가변적인 수의 몫 자릿수를 계산하며 일반적으로 더 비쌉니다. 나눗셈 방법에서 가장 중요한 부분은 대부분 의 역수를 근사화하여 의 반복 곱셈에 의존하므로 오류가 발생하기 쉽다는 것입니다.

4. 다른 작업의 반올림 오류: 잘림

모든 작업에서 반올림 오류가 발생하는 또 다른 원인은 IEEE-754에서 허용하는 다양한 잘림 모드입니다. 잘림, 0으로 반올림, 가장 가까운 반올림(기본값) , 반올림, 반올림이 있습니다. 모든 방법은 단일 작업에 대해 마지막 비트의 절반 미만 단위의 오류를 발생시킵니다. 시간이 지남에 따라 작업이 반복되면서 잘림이 누적되어 결과 오류가 발생합니다. 이 잘림 오류는 어떤 형태의 반복 곱셈과 관련된 지수 연산에서 특히 문제가 됩니다.

5. 작업을 반복하세요

부동 소수점 계산을 수행하는 하드웨어는 단일 작업에서 장치의 마지막 비트 오류의 절반 미만의 결과만 생성하면 되므로 관찰하지 않고 방치하면 작업이 반복됨에 따라 오류가 증가합니다. 이것이 제한된 오류가 필요한 계산에서 수학자들이 IEEE-754의 가장 가까운 반올림 짝수를 사용하는 것과 같은 방법을 사용하는 이유입니다. 오류는 시간이 지남에 따라 서로 상쇄될 가능성이 높기 때문이며, 간격 산술 IEEE 754의 변형을 통합합니다. 반올림 모드로 반올림 오류를 예측하고 수정합니다. 가장 가까운 짝수(마지막 비트)로 반올림하는 것은 다른 반올림 모드에 비해 상대적 오류가 낮기 때문에 IEEE-754의 기본 반올림 모드입니다.

가장 가까운 짝수로 반올림하는 기본 반올림 모드는 마지막 자리의 1/2 단위 미만의 오류로 연산을 보장한다는 점에 유의하세요. 잘라내기, 반올림 및 내림만 사용하면 마지막 숫자의 1/2 단위보다 크고 마지막 숫자의 1 단위 미만의 오류가 발생할 수 있으므로 간격으로 계산하지 않는 한
P粉041881924

바이너리부동소수점 연산은 이렇습니다. 대부분의 프로그래밍 언어에서는 IEEE 754 표준을 기반으로 합니다. 문제의 핵심은 숫자가 이 형식에서 정수 곱하기 2의 거듭제곱으로 표현된다는 것입니다. 분모가 2의 거듭제곱이 아닌 유리수(예: 0.1,即1/10)는 정확하게 표현될 수 없습니다.

표준 binary64格式中的0.1의 경우 표현은

로 정확하게 작성할 수 있습니다.

반대로 유리수 0.1,即1/10는 다음과 같이 정확하게 쓸 수 있습니다.

  • 0.1(십진수) 또는
  • 0x1.99999999999999...p-4(类似于C99十六进制浮点表示法,其中...은 9)의 끝없는 시퀀스를 나타냅니다.

프로그램의 상수 0.20.3도 실제 값의 근사치입니다. 정확히 0.2 가장 가까운 double은 유리수 0.2보다 크지만 가장 가까운 double은 유리수보다 작습니다. 번호 0.3. 0.20.3也将是它们真实值的近似值。恰好0.2最接近的double大于有理数0.2,但最接近的double小于有理数0.30.10.2的和最终大于有理数0.30.2의 합은 유리수 0.3보다 커지므로 코드의 상수와 일치하지 않습니다.

부동 소수점 연산에 대한 상당히 포괄적인 처리 방법은 "컴퓨터 과학자가 부동 소수점 연산에 대해 알아야 할 사항"입니다. 더 이해하기 쉬운 설명은 floating-point-gui.de를 참조하세요.

일반 십진수(10진수)에도 동일한 문제가 존재합니다. 이것이 바로 1/3과 같은 숫자가 0.333333333으로 끝나는 이유입니다...

십진법으로는 쉽게 표현되지만 이진법으로는 표현할 수 없는 숫자(3/10)를 만났습니다. 상황은 어떤 면에서는 반대입니다. 1/16은 십진수(0.0625)에서는 보기 흉한 숫자이지만 십진수에서는 1/10000(0.0001)처럼 이진수에서는 깔끔하게 보입니다** - 이진수 사용에 익숙했다면 일상생활에서 시스템을 사용한다면 그 숫자를 보고 계속해서 반으로 접어서 얻을 수 있다는 것을 본능적으로 이해하게 될 것입니다.

물론 이것은 부동 소수점 숫자가 메모리에 저장되는 방식과 정확히 일치하지는 않습니다(과학적 표기법 형식을 사용함). 그러나 이는 우리가 일반적으로 관심을 갖는 "실제" 숫자가 10의 거듭제곱인 경향이 있기 때문에 이진 부동 소수점 정밀도 오류가 발생하는 경향이 있다는 문제를 보여줍니다. 그러나 이는 우리가 매일 십진수 시스템을 사용하기 때문입니다. 이것이 바로 "7/7 중 5" 대신에 71%라고 말하는 이유입니다. (71%는 대략적인 수치입니다. 소수는 5/7을 정확하게 나타낼 수 없기 때문입니다.)

아니요, 이진 부동 소수점 숫자는 깨지지 않고 다른 기본 N 숫자 시스템처럼 불완전할 뿐입니다 :)

실제로 이 정밀도 문제는 부동 소수점 수를 표시하기 전에 관심 있는 소수 자릿수로 반올림하는 반올림 기능을 사용해야 함을 의미합니다.

동등성 테스트를 특정 허용오차를 허용하는 비교로 대체해야 합니다. 즉,

사용하지 마세요if (x == y) { ... }

대신 if (abs(x - y) < myToleranceValue) { ... }을 사용하세요.

위치 abs是绝对值函数。需要根据您的特定应用选择myToleranceValue - 이는 허용할 준비가 되어 있는 "흔들기 공간"의 양과 비교할 최대 수(정밀도 손실 문제로 인해)와 많은 관련이 있습니다. 선택한 언어의 "epsilon" 스타일 상수를 참고하세요. 이러한 상수는 공차 값으로 사용될 수 있지만 그 효과는 작업 중인 숫자의 크기에 따라 달라집니다(큰 숫자 계산은 엡실론 임계값을 초과할 수 있으므로).

최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿