Ось що відбувається у двійковому. Як ми знаємо, деякі значення з плаваючою комою не можуть бути представлені точно у двійковій формі, навіть якщо вони можуть бути представлені точно у десятковій формі. Ці 3 числа - лише приклади цього факту.
За допомогою цієї програми я виводить шістнадцяткові подання кожного числа та результати кожного додавання.
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Метод просто помічник шестигранного принтера.
Вихід такий:
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, останні 2 біти другого числа ( 01) зміщуються поза діапазоном і не враховуються в обчисленні.
Друге додавання додає x + yі zдодає два числа однакової шкали.
Другий набір доповнень
Тут, x + zвідбувається спочатку. Вони однакової шкали, але дають число, яке вище за шкалою:
404 => 0|100 0000 0100| => 1028 - 1023 = 5
Друге додавання додає x + zі y, і тепер для додавання чисел ( ) випадають 3 біти . Тут має бути кругле вгору, тому що результат - наступне число з плаваючою комою вгору: для першого набору доповнень проти другого набору доповнень. Ця помилка є достатньо істотною для відображення у роздруківці загальної кількості.y10140478666666666664047866666666667
На закінчення будьте обережні, виконуючи математичні операції над номерами IEEE. Деякі уявлення неточні, і вони стають ще більш неточними, коли масштаби різні. Додайте і віднімайте числа аналогічного масштабу, якщо зможете.
(2.0^53 + 1) - 1 == 2.0^53 - 1 != 2^53 == 2^53 + (1 - 1)). Отже, так: будьте обережні, обираючи порядок сум та інших операцій. Деякі мови надають вбудований для виконання "високоточних" сум (наприклад, pythonmath.fsum), тому ви можете розглянути можливість використання цих функцій замість алгоритму наївної суми.