Модуль с удваивается в Java

Как Вы имеете дело со странным поведением Java с оператором модуля, когда использование удваивается?

Например, Вы ожидали бы результат 3.9 - (3.9 % 0.1) быть 3.9 (и действительно, Google говорит, что я не схожу с ума), но когда я выполняю его в Java, я добираюсь 3.8000000000000003.

Я понимаю, что это - результат того, как хранилища Java и процессы удваиваются, но являются там способом работать вокруг этого?

12
задан Andy 12 July 2010 в 09:38
поделиться

4 ответа

Используйте точный тип, если вам нужен точный результат:

    double val = 3.9 - (3.9 % 0.1);
    System.out.println(val); // 3.8000000000000003

    BigDecimal x = new BigDecimal( "3.9" );
    BigDecimal bdVal = x.subtract( x.remainder( new BigDecimal( "0.1" ) ) );
    System.out.println(bdVal); // 3.9

Почему 3.8000...003? Потому что Java использует FPU для вычисления результата. 3.9 невозможно сохранить точно в IEEE двойной точности нотации, поэтому он хранит 3.89999... вместо. А 3,8999%0,01 дает 0,09999... следовательно, результат немного больше, чем 3,8.

18
ответ дан 2 December 2019 в 06:07
поделиться

Вы можете использовать java.math.BigDecimal и его метод divideAndRemainder().

2
ответ дан 2 December 2019 в 06:07
поделиться

Если вы знаете количество десятичных знаков, с которыми имеете дело, вы можете сначала попытаться преобразовать их в целые числа. Это просто классический случай неточности с плавающей запятой. Вместо 3.9% 0.1 вы делаете что-то вроде 3.899% 0.0999

1
ответ дан 2 December 2019 в 06:07
поделиться

Из Спецификация языка Java :

Результат числа с плавающей запятой операция остатка, вычисленная Оператор% отличается от этого произведенный остальной операцией определено IEEE 754. IEEE 754 операция остатка вычисляет остаток от округления, не усекающее деление, и поэтому его поведение не аналогично поведению обычный оператор целочисленного остатка. Вместо этого язык программирования Java определяет% для операций с плавающей запятой вести себя аналогично что из целочисленного остатка оператор; это можно сравнить с библиотечная функция C fmod. IEEE 754 операция остатка может быть вычисляется библиотечной подпрограммой Math.IEEE Остаток.

Другими словами, это связано с тем, что Java округляет результат деления, участвующего в вычислении остатка, в то время как IEEE754 определяет усечение ответа деления. Этот конкретный случай, кажется, очень ясно показывает эту разницу.

Вы можете получить ожидаемый ответ, используя Math.IEEEremainder:

System.out.println(3.9 - (3.9 % 0.1));
System.out.println(3.9 - Math.IEEEremainder(3.9, 0.1));
4
ответ дан 2 December 2019 в 06:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: