P粉5205457532023-10-12 10:27:06
저는 부동 소수점 하드웨어를 설계하고 구축하기 때문에 하드웨어 디자이너의 관점을 추가해야 한다고 생각합니다. 오류의 원인을 아는 것은 소프트웨어에서 무슨 일이 일어나고 있는지 이해하는 데 도움이 될 수 있으며, 궁극적으로 부동 소수점 오류가 발생하고 시간이 지남에 따라 누적되는 것처럼 보이는 이유를 설명하는 데 도움이 되기를 바랍니다.
엔지니어링 관점에서 볼 때, 부동 소수점 계산을 수행하는 하드웨어는 마지막 비트에서 단위의 1/2 미만의 오류만 있으면 되기 때문에 대부분의 부동 소수점 연산에는 약간의 오류가 있습니다. 따라서 많은 하드웨어는 단일 연산의 마지막 비트만 필요로 하는 정밀도에서 중지되어 1단위 미만의 오류를 생성하며, 이는 부동 소수점 나눗셈에서 특히 문제가 됩니다. 단일 연산을 구성하는 것은 해당 단위에 필요한 피연산자 수에 따라 다릅니다. 대부분의 경우 2개이지만 일부 장치에는 3개 이상의 피연산자가 필요합니다. 따라서 시간이 지남에 따라 오류가 누적되므로 반복 작업으로 인해 원하는 오류가 발생한다는 보장이 없습니다.
대부분의 프로세서는 IEEE-754 표준을 따르지만 일부는 비정규화되거나 다른 표준을 사용합니다. . 예를 들어, IEEE-754에는 정밀도를 희생하면서 매우 작은 부동 소수점 숫자를 표현할 수 있는 비정규화 모드가 있습니다. 그러나 아래에서는 일반적인 동작 모드인 IEEE-754의 표준화된 모드에 대해 설명합니다.
IEEE-754 표준에서 하드웨어 설계자는 마지막 숫자 단위의 1/2 미만인 한 모든 오류/엡실론 값을 사용할 수 있으며 결과는 1/2 미만이면 됩니다. 한번에 사용되는 단위 연산의 마지막 위치입니다. 이는 작업이 반복될 때 오류가 누적되는 이유를 설명합니다. IEEE-754 배정밀도의 경우 비트 53이 가수(예: 5.3e5의 5.3)라고도 알려진 부동 소수점 숫자의 숫자 부분(정규화)을 나타내는 데 사용되므로 이는 비트 54입니다. 다음 섹션에서는 다양한 부동 소수점 연산에서 하드웨어 오류가 발생하는 원인에 대해 자세히 설명합니다.
부동소수점 나눗셈 오류의 주요 원인은 몫을 계산하는 데 사용되는 나눗셈 알고리즘입니다. 대부분의 컴퓨터 시스템은 역곱셈을 사용하여 주로 Z=X/Y
、Z = X * (1/Y)
。除法是迭代计算的,即每个周期计算商的一些位,直到达到所需的精度,对于 IEEE-754 来说,精度是最后一位误差小于一个单位的任何值。 Y(1/Y)的倒数表在慢除法中被称为商选择表(QST),商选择表的大小(以位为单位)通常是基数的宽度,或者是基数的位数。每次迭代中计算的商,加上一些保护位。对于 IEEE-754 标准,双精度(64 位),它是除法器基数的大小,加上一些保护位 k,其中 k>=2
。例如,一次计算 2 位商(基数 4)的除法器的典型商选择表将是 2+2= 4
비트(몇 가지 선택적 비트 포함)의 나눗셈을 계산합니다.
3.1 나눗셈 반올림 오류: 역수의 근사
몫 선택 테이블의 역수는 나눗셈에 따라 다릅니다. SRT 나눗셈과 같은 느린 나눗셈 또는 Goldschmidt 나눗셈과 같은 빠른 나눗셈은 가능한 가장 낮은 오류를 생성하기 위해 나눗셈 알고리즘에 따라 수정됩니다. 그럼에도 불구하고 모든 역수는 실제 역수의 근사치이며 일부 오류 요소가 발생합니다. 느린 나눗셈과 빠른 나눗셈 모두 반복적으로 몫을 계산합니다. 즉, 각 단계는 몫의 자릿수를 계산한 다음 피제수에서 결과를 뺍니다. 나눗셈은 마지막 위치에서 오류가 1/2 단위 미만이 될 때까지 이러한 단계를 반복합니다. . 느린 나누기 방법은 각 단계에서 고정된 자릿수의 몫을 계산하고 일반적으로 구축 비용이 덜 드는 반면, 빠른 나누기 방법은 각 단계에서 가변 자릿수를 계산하고 일반적으로 구축하는 데 더 많은 비용이 듭니다. 나눗셈에서 가장 중요한 부분은 대부분 역수 근사의 반복적인 곱셈에 의존하므로 실수하기 쉽다는 것입니다.
모든 작업에서 반올림 오류가 발생하는 또 다른 이유는 IEEE-754에서 허용하는 최종 답의 잘림 모드가 다르기 때문입니다. 잘림, 0으로 반올림, 가장 가까운 반올림(기본값), 반올림, 반올림이 있습니다. 단일 작업의 경우 모든 방법은 마지막에 1단위 미만의 오류 요소를 도입합니다. 또한 잘림은 시간이 지남에 따라 반복 작업을 통해 최종 오류를 누적적으로 증가시킵니다. 이러한 잘림 오류는 지수 계산에 어떤 형태의 반복 곱셈이 포함될 때 특히 문제가 됩니다.
부동소수점 계산을 수행하는 하드웨어는 한 번의 작업으로 마지막 비트의 오류가 절반 미만인 결과만 생성하면 되므로 주의하지 않으면 작업을 반복할수록 오류가 증가합니다. 이것이 제한된 오류가 필요한 계산에서 수학자들이 가장 가까운 간격 산술 을 IEEE 754 반올림 모드 변형과 결합하여 반올림 오류를 예측하고 수정합니다. 가장 가까운 짝수(마지막 숫자)로 반올림하는 것은 다른 반올림 모드에 비해 상대 오차가 낮기 때문에 IEEE-754의 기본 반올림 모드입니다.
기본 반올림 모드는 마지막 숫자의 가장 가까운 짝수 a>로 반올림되므로 한 번의 작업에서 마지막 숫자의 오류가 절반 미만이 되도록 합니다. 잘림, 반올림 및 반내림만 수행하면 마지막 숫자의 1/2보다 크고 마지막 숫자의 1단위 미만의 오류가 발생할 수 있으므로 이러한 모드는 간격 산술을 제외하고는 권장되지 않습니다.
즉, 부동 소수점 연산 오류의 근본 원인은 하드웨어 잘림과 나누기 중 역잘림의 조합입니다. IEEE-754 표준에서는 단일 작업의 마지막 비트 오류가 1/2 미만이어야 하기 때문에 수정되지 않으면 반복 작업으로 인한 부동 소수점 오류가 누적됩니다.
P粉5634465792023-10-12 10:02:37
바이너리 부동소수점수학은 이런 겁니다. 대부분의 프로그래밍 언어에서는 IEEE 754 표준을 기반으로 합니다. 문제의 핵심은 숫자가 2의 거듭제곱을 곱한 정수로 이 형식으로 표현된다는 것입니다. 분모가 2의 거듭제곱이 아닌 유리수(예: 0.1
,即1/10
)는 정확하게 표현할 수 없습니다.
표준 binary64
格式的 0.1
의 경우 표현은
0.10000000000000000055511151231257827021181583404541015625
(십진수) 또는 0x1.999999999999ap-4
C99 16진수 부동 소수점 표현< /a>.반대로 유리수0.1
,即1/10
는 다음과 같이 정확하게 쓸 수 있습니다.
0.1
(십진수) 또는 0x1.99999999999999...p-4
类似于 C99 十六进制浮点表示法,其中 ...
은 9가 끝없이 연속되는 것을 의미합니다. 프로그램의 상수 0.2
및 0.3
도 실제 값의 근사치입니다. 공교롭게도 0.2
에 가장 가까운 double
은 유리수 0.2
보다 크지만 double
에 가장 가깝습니다. code>0.3 유리수 0.3
보다 작습니다. 0.2
和0.3
也将是其真实值的近似值。碰巧,最接近 0.2
的 double
大于有理数 0.2
,但最接近 double
code>0.3 小于有理数 0.3
。 0.1
和 0.2
的总和最终大于有理数 0.3
와 0.2
의 합은 유리수 0.3
보다 커지므로 코드의 상수와 일치하지 않습니다.
부동 소수점 산술 문제에 대한 상당히 포괄적인 처리 방법은 모든 컴퓨터 과학자가 부동 소수점 산술에 대해 알아야 하는입니다. 더 이해하기 쉬운 설명은 floating-point-gui.de를 참조하세요.
일반 십진수(10진법) 숫자에도 같은 문제가 있습니다. 이것이 바로 1/3과 같은 숫자가 결국 0.333333333이 되는 이유입니다...
십진법으로는 쉽게 표현되지만 이진법으로는 표현되지 않는 숫자(3/10)를 우연히 발견하셨습니다. 또한 어느 정도 양방향으로 진행됩니다. 1/16은 십진수로 보기 흉한 숫자(0.0625)이지만 이진수로 보면 십진수 10,000번째 숫자(0.0001)**처럼 보입니다. 일상 생활에서 2진수 체계를 사용하는 습관이 생기면 숫자를 보고 본능적으로 무엇인가를 반으로 나누고, 반으로 나누고, 계속 반복해서 그 숫자에 도달할 수 있다는 것을 이해하게 될 것입니다.
물론 이것은 부동 소수점 숫자가 메모리에 저장되는 방식과 정확히 일치하지는 않습니다(과학적 표기법을 사용함). 그러나 이는 우리가 일반적으로 관심을 갖는 "실제" 숫자가 일반적으로 10의 거듭제곱이기 때문에 이진 부동 소수점 정밀도 오류가 발생하는 경향이 있음을 보여줍니다. 그러나 이는 오늘날 우리가 십진수 체계를 사용하기 때문입니다. 이것이 바로 "7/7" 대신에 71%라고 말하는 이유입니다(71%는 대략적인 값입니다. 5/7은 어떤 십진수로도 정확하게 표현할 수 없기 때문입니다).
아니요: 이진 부동 소수점 숫자는 깨지지 않으며 다른 모든 N 기반 숫자 시스템처럼 불완전할 뿐입니다 :)
실제로 이 정밀도 문제는 부동 소수점 숫자를 표시하기 전에 관심 있는 소수 자릿수로 반올림하기 위해 반올림 기능을 사용해야 함을 의미합니다.
동등성 테스트를 어느 정도 허용하는 비교로 대체해야 합니다. 즉, 다음을 의미합니다.
하지 하지 하지 if (x == y) { ... }
대신 실행if (abs(x - y) < myToleranceValue) { ... }
.
특정 애플리케이션에 따라 abs
是绝对值。 myToleranceValue
를 선택해야 합니다. 허용할 준비가 되어 있는 "흔들기 공간"과 많은 관련이 있으며 비교하는 가장 큰 숫자가 될 가능성이 높습니다(정밀도 손실 문제로 인해). . 선택한 언어의 "엡실론" 스타일 상수를 확인하세요. 이러한 는 공차 값으로 사용될 수 있지만 큰 숫자에 대한 계산은 엡실론 임계값을 초과할 수 있으므로 작업 중인 숫자의 크기에 따라 그 효과가 달라집니다.