Ответ 1
Я согласен с предыдущим ответом jmcnamara. Этот ответ расширяется.
Для каждого 64-битного двоичного числа с плавающей запятой IEEE 754 существует диапазон десятичных дробей, которые бы округляли его на входе. Начиная с -130.98999999999069, самым близким представляемым значением является -130.98999999999068677425384521484375. При раунде до ближайшего с раундом половина даже правил, все в диапазоне [-130.9899999999907009851085604168474674224853515625, -130.9899999999906725633991300128400325775146484375] раундов до этого значения. (Диапазон закрыт, потому что двоичное представление центрального номера четное. Если бы оно было нечетным, диапазон был бы открытым). И -130.98999999999069, и -130.9899999999907 находятся в диапазоне.
У вас есть тот же номер с плавающей запятой, что и Excel.
У вас есть тот же номер с плавающей запятой, который был введен в Excel. К сожалению, дальнейшие эксперименты показывают, что Excel 2007 только преобразует наиболее важные 15 цифр вашего ввода. Я вставил -130.98999999999069 в ячейку Excel. Мало того, что оно отображалось как -130.98999999999, арифметическое использование было согласовано с ближайшим двойным к этому значению, -130.989999999990004653227515518665313720703125, а не исходным входом.
Чтобы получить тот же эффект, что и Excel, вам может потребоваться использовать, например. BigDecimal для усечения до 15 десятичных цифр, затем преобразование в double.
Преобразование строк Java по умолчанию для значений с плавающей запятой в основном выбирает десятичную дробь с наименьшим количеством знаков после запятой, которые будут конвертировать обратно в исходное значение. -130.9899999999907 имеет меньше десятичных знаков, чем -130.98999999999069. По-видимому, Excel отображает меньше цифр, но Apache POI получает одно из представлений того же числа, что и в Java.
Вот программа, которую я использовал для получения чисел в этом ответе. Обратите внимание, что я использую BigDecimal только для получения точных распечаток удвоений и вычисления средней точки между двумя последовательными удвоениями.
import java.math.BigDecimal;
class Test {
public static void main(String[] args) {
double d = -130.98999999999069;
BigDecimal dDec = new BigDecimal(d);
System.out.println("Printed as double: "+d);
BigDecimal down = new BigDecimal(Math.nextAfter(d, Double.NEGATIVE_INFINITY));
System.out.println("Next down: " + down);
System.out.println("Half down: " + down.add(dDec).divide(BigDecimal.valueOf(2)));
System.out.println("Original: " + dDec);
BigDecimal up = new BigDecimal(Math.nextAfter(d, Double.POSITIVE_INFINITY));
System.out.println("Half up: " + up.add(dDec).divide(BigDecimal.valueOf(2)));
System.out.println("Next up: " + up);
System.out.println("Original in hex: "+Long.toHexString(Double.doubleToLongBits(d)));
}
}
Вот его вывод:
Printed as double: -130.9899999999907
Next down: -130.989999999990715195963275618851184844970703125
Half down: -130.9899999999907009851085604168474674224853515625
Original: -130.98999999999068677425384521484375
Half up: -130.9899999999906725633991300128400325775146484375
Next up: -130.989999999990658352544414810836315155029296875
Original in hex: c0605fae147ae000