바이너리로 진행되는 일이 있습니다. 우리가 알다시피, 일부 부동 소수점 값은 정확히 10 진수로 표현 될 수 있다고하더라도 바이너리로 정확하게 표현 될 수 없습니다. 이 세 숫자는 그 사실의 예일뿐입니다.
이 프로그램으로 각 숫자의 16 진수 표현과 각 덧셈의 결과를 출력했습니다.
public class Main{
public static void main(String args[]) {
double x = 23.53; // Inexact representation
double y = 5.88; // Inexact representation
double z = 17.64; // Inexact representation
double s = 47.05; // What math tells us the sum should be; still inexact
printValueAndInHex(x);
printValueAndInHex(y);
printValueAndInHex(z);
printValueAndInHex(s);
System.out.println("--------");
double t1 = x + y;
printValueAndInHex(t1);
t1 = t1 + z;
printValueAndInHex(t1);
System.out.println("--------");
double t2 = x + z;
printValueAndInHex(t2);
t2 = t2 + y;
printValueAndInHex(t2);
}
private static void printValueAndInHex(double d)
{
System.out.println(Long.toHexString(Double.doubleToLongBits(d)) + ": " + d);
}
}
이 printValueAndInHex
방법은 16 진수 프린터 도우미입니다.
출력은 다음과 같습니다.
403787ae147ae148: 23.53
4017851eb851eb85: 5.88
4031a3d70a3d70a4: 17.64
4047866666666666: 47.05
--------
403d68f5c28f5c29: 29.41
4047866666666666: 47.05
--------
404495c28f5c28f6: 41.17
4047866666666667: 47.050000000000004
처음 4 개 번호는 x
, y
, z
, 및 s
의 진수 표현. IEEE 부동 소수점 표현에서 비트 2-12는 이진 지수 즉 숫자의 스케일을 나타냅니다 . (첫 번째 비트는 부호 비트이고, 가수에 대한 나머지 비트입니다 .) 표현 된 지수는 실제로 이진수에서 1023을 뺀 것입니다.
처음 4 개의 지수가 추출됩니다.
sign|exponent
403 => 0|100 0000 0011| => 1027 - 1023 = 4
401 => 0|100 0000 0001| => 1025 - 1023 = 2
403 => 0|100 0000 0011| => 1027 - 1023 = 4
404 => 0|100 0000 0100| => 1028 - 1023 = 5
추가의 첫 세트
두 번째 숫자 ( y
)는 더 작은 크기입니다. 를 얻기 위해이 두 숫자를 더할 때 두 x + y
번째 숫자 ( 01
) 의 마지막 2 비트 가 범위를 벗어나 계산에 포함되지 않습니다.
제 첨가 추가 x + y
와 z
같은 규모의 두 숫자를 추가한다.
추가의 두 번째 세트
여기서 x + z
먼저 발생합니다. 그것들은 같은 규모이지만, 규모가 더 높은 숫자를 산출합니다.
404 => 0|100 0000 0100| => 1028 - 1023 = 5
제 첨가를 추가 x + z
하고 y
, 현재 3 비트로부터 삭제되는 y
숫자를 추가 ( 101
). 결과는 다음 부동 소수점 수이기 때문에 위쪽으로 반올림되어야합니다 4047866666666666
. 첫 번째 덧셈 4047866666666667
세트와 두 번째 덧셈 세트의 결과입니다. 이 오류는 총계의 출력물에 표시하기에 충분히 중요합니다.
결론적으로 IEEE 숫자에 대해 수학 연산을 수행 할 때주의하십시오. 일부 표현은 정확하지 않으며 스케일이 다르면 훨씬 더 정확하지 않습니다. 가능하면 비슷한 규모의 숫자를 더하고 빼십시오.
(2.0^53 + 1) - 1 == 2.0^53 - 1 != 2^53 == 2^53 + (1 - 1)
. 따라서, 예 : 합계 및 기타 작업의 순서를 선택할 때주의하십시오. 일부 언어는 "고정밀"합계 (예 : python 'smath.fsum
) 를 수행하기위한 내장 기능을 제공 하므로 순진 합계 알고리즘 대신 이러한 함수를 사용하는 것이 좋습니다.