Почему использование по модулю для нецелочисленных значений теряет точность с плавающей запятой?

Мне интересно, почему я теряю точность при использовании этого кода:

double x = 12.0456;    // or float : same result
System.out.println(x); // outputs 12.0456 obviously
x %= 1;                // should now be equal to 0.0456 right?
System.out.println(x); // outputs 0.04560000000000031 or 0.045599937 when using float

12,0456 по модулю 1 должно равняться 0,0456, верно? Но он показывает немного другое значение, почему я все время теряю точность? Я имею в виду, что код должен вычитать ровно 1, пока значение не станет меньше 1.

Однако я нашел способ получить правильное значение:

double x = 12.0456;
System.out.println(x);
x %= 1;
System.out.println((float)x); //outputs 0.0456 exactly

Этот способ работает отлично, но есть ли у вас решение получше?

Мне все равно, какой тип с плавающей запятой мне следует использовать, я просто хочу найти простой способ получить правильное значение! Мне не нравится преобразовывать значение в двойное, а затем в поплавок.


person dominicbri7    schedule 09.02.2013    source источник
comment
Вам нужно прочитать об использовании чисел с плавающей запятой в Java. Ваш результат ожидаемый и правильный.   -  person BeRecursive    schedule 10.02.2013
comment
На практике двойники точны только до 6-8 значащих цифр.   -  person Code-Apprentice    schedule 10.02.2013
comment
BeRecursive, знаете ли вы, как получить желаемый результат, будучи ожидаемым и правильным?   -  person dominicbri7    schedule 10.02.2013
comment
@ dominicbri7 floats и doubles просто не могут представлять любое произвольное действительное число. Если вам нужно поддерживать известную точность, используйте BigDecimals, но даже они имеют только произвольную точность, а не бесконечную точность. (Это может не иметь практического значения.)   -  person millimoose    schedule 10.02.2013
comment
@ Code-Guru Doubles «на практике» точны до 14-15 десятичных цифр: меньше так, если есть дроби, и таким образом, который не может быть сокращен до простого числа десятичных знаков. Это зависит от фактического значения.   -  person user207421    schedule 10.02.2013


Ответы (1)


Float и double неточны - у них есть конечное количество бит для представления значения.

Поскольку люди используют основание 10, а компьютеры используют основание 2, числа, которые кажутся нам «простыми», невозможно точно представить как числа с плавающей запятой / двойным числом, особенно результаты вычислений из-за того, как их выполняют процессоры.

person Bohemian♦    schedule 09.02.2013
comment
Чтобы добавить к своему ответу, возьмем для примера дробь 1/3. Это невозможно точно представить с помощью конечного числа десятичных знаков. Подобные проблемы возникают с двоичным представлением чисел с плавающей запятой. - person Code-Apprentice; 11.02.2013