Я подозреваю, что разница заключается в преобразовании 80-разрядного значения с плавающей запятой в длинное по сравнению с преобразованием из 80-разрядного значения с плавающей запятой в 64-разрядное и , затем преобразование в длинный.
(Причиной появления 80 битов является то, что это типичная точность, используемая для фактической арифметики и ширины регистров с плавающей запятой.)
Предположим, что 80-битный результат - что-то вроде 10.999999999999999 - преобразование из этого значения в длинное дает 10. Однако самое близкое 64-битное значение с плавающей запятой к 80-битному значению фактически равно 11.0, поэтому двухэтапное преобразование в конечном итоге уступает 11.
РЕДАКТИРОВАТЬ: Чтобы придать этому немного больший вес ...
Вот программа на Java, которая использует арифметику произвольной точности для того же вычисления. Обратите внимание, что он преобразует значение типа Double, ближайшее к 0,1, в значение BigDecimal - это значение равно 0,1000000000000000055511151231257827021181583404541015625. (Другими словами, точный результат вычисления равен , а не 11.)
import java.math.*;
public class Test
{
public static void main(String[] args)
{
BigDecimal c = new BigDecimal(0.1d);
BigDecimal a = new BigDecimal(1d);
BigDecimal b = new BigDecimal(2d);
BigDecimal result = b.subtract(a)
.add(c)
.divide(c, 40, RoundingMode.FLOOR);
System.out.println(result);
}
}
Вот результат:
10.9999999999999994448884876874217606030632
Другими словами, это правильно с точностью до 40 десятичных цифр (гораздо больше, чем может обработать 64-битная или 80-битная плавающая точка).
Теперь давайте рассмотрим, как выглядит это число в двоичном виде. У меня нет никаких инструментов, чтобы легко сделать преобразование, но снова мы можем использовать Java, чтобы помочь. Предполагая нормализованное число, часть «10» заканчивается использованием трех битов (один меньше, чем для одиннадцати = 1011). Это оставляет 60 бит мантиссы для расширенной точности (80 бит) и 48 бит для двойной точности (64 бит).
Итак, какое число ближе к 11 в каждой точности? Опять же, давайте использовать Java:
import java.math.*;
public class Test
{
public static void main(String[] args)
{
BigDecimal half = new BigDecimal("0.5");
BigDecimal eleven = new BigDecimal(11);
System.out.println(eleven.subtract(half.pow(60)));
System.out.println(eleven.subtract(half.pow(48)));
}
}
Результаты:
10.999999999999999999132638262011596452794037759304046630859375
10.999999999999996447286321199499070644378662109375
Итак, у нас есть три числа:
Correct value: 10.999999999999999444888487687421760603063...
11-2^(-60): 10.999999999999999999132638262011596452794037759304046630859375
11-2^(-48): 10.999999999999996447286321199499070644378662109375
Теперь вычислите наиболее близкое к правильному значение для каждой точности - для расширенной точности оно меньше, чем 11. Округлите каждое из этих значений до длинного, и вы получите 10 и 11 соответственно.
Надеюсь, этого достаточно, чтобы убедить сомневающихся;)