Арифметика с плавающей точкой не создание точных результатов [дубликат]

, Если Вы ищете способ применить "статическое" ключевое слово к классу, как Вы, может в C#, например

, статические классы являются просто содержанием руки компилятора Вы и мешать Вам писать любые методы/переменные экземпляра.

, Если Вы просто пишете нормальный класс без каких-либо методов/переменных экземпляра, это - то же самое, и это - то, что Вы сделали бы в C++

31
задан Andrew Thompson 27 March 2014 в 07:18
поделиться

5 ответов

Если вам нужны точные десятичные значения, вы должны использовать java.math.BigDecimal . Затем прочтите «Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой» , чтобы узнать, почему вы получаете такие результаты.

(У меня есть .NET-ориентированная статья ], которую вам будет легче читать - и, конечно, короче. Различия между Java и .NET в основном не имеют значения для понимания этой проблемы.)

33
ответ дан 27 November 2019 в 22:25
поделиться

В числах с плавающей запятой используются двоичные дроби, а не десятичные дроби. То есть вы привыкли к десятичным дробям, состоящим из десятых, сотых, тысячных и т. Д. D1 / 10 + d2 / 100 + d3 / 1000 ... Но числа с плавающей запятой являются двоичными, поэтому они имеют половину, четверть, восьмую цифру и т. д. d1 / 2 + d2 / 4 + d3 / 8 ...

Многие десятичные дроби не могут быть точно выражены каким-либо конечным числом двоичных цифр. Например, 1/2 - не проблема: в десятичной системе - 0,5, в двоичной - 0,1. 3/4 - это десятичное 0,75, двоичное 0,11. Но 1/10 - это чистый 0,1 в десятичном виде, а в двоичном - 0,0001100110011 ... с бесконечным повторением «0011». Поскольку компьютер может хранить только конечное число цифр, в какой-то момент его нужно обрубить, поэтому ответ будет неточным. Когда мы преобразуем обратно в десятичную форму на выходе, мы получаем странное число.

Как говорит Джон Скит, если вам нужны точные десятичные дроби, используйте BigDecimal. Если производительность является проблемой, вы можете использовать собственные десятичные дроби. Например, если вы знаете, что всегда хотите ровно 3 десятичных знака и что числа не будут больше миллиона или около того, вы можете просто использовать int с предполагаемыми 3 десятичными знаками, внося необходимые корректировки, когда вы выполняете арифметические операции и записываете результат Функция форматирования для вставки десятичной точки в нужное место. Но в 99% случаев производительность не является настолько большой проблемой, чтобы стоить затраченных усилий.

если вы знаете, что вам всегда нужно ровно 3 десятичных разряда и что числа не будут больше миллиона или около того, вы можете просто использовать int с предполагаемыми 3 десятичными знаками, внося необходимые корректировки при выполнении арифметических операций и написании функции формата вывода чтобы вставить десятичную точку в нужное место. Но в 99% случаев производительность не является настолько большой проблемой, чтобы стоить затраченных усилий.

если вы знаете, что вам всегда нужно ровно 3 десятичных знака и что числа не будут больше миллиона или около того, вы можете просто использовать int с предполагаемыми 3 десятичными знаками, внося необходимые корректировки при выполнении арифметических операций и написании функции формата вывода чтобы вставить десятичную точку в нужное место. Но в 99% случаев производительность не является настолько большой проблемой, чтобы стоить усилий.

11
ответ дан 27 November 2019 в 22:25
поделиться

Числа с плавающей запятой неточны, особенно потому, что они работают с двоичными дробями (1/2, 1/4, 1/8, 1/16, 1/32, ...) вместо десятичных дробей (1/10, 1 / 100, 1/1000, ...). Просто определите, что вы считаете «достаточно близким», и используйте что-нибудь вроде Math.abs (ab) <0.000001 .

) вместо десятичных дробей (1/10, 1/100, 1/1000, ...). Просто определите, что вы считаете «достаточно близким», и используйте что-нибудь вроде Math.abs (ab) <0.000001 .

) вместо десятичных дробей (1/10, 1/100, 1/1000, ...). Просто определите, что вы считаете «достаточно близким», и используйте что-нибудь вроде Math.abs (ab) <0.000001 .

3
ответ дан 27 November 2019 в 22:25
поделиться

С философской точки зрения, интересно: большинство компьютерных процессоров сегодня имеют встроенную поддержку целочисленной арифметики и арифметики с плавающей запятой, но не поддерживают десятичную арифметику. Почему бы нет? Я много лет не писал приложений, в которых можно было бы использовать числа с плавающей запятой из-за этой проблемы округления. Вы, конечно, не можете использовать их для денежных сумм: никто не хочет печатать цену на товарном чеке «42,3200003 доллара». Ни один бухгалтер не согласится с тем, что «мы можем потерять копейки здесь и там, потому что мы используем двоичные дроби и имели ошибки округления».

Поплавки подходят для измерений, таких как расстояние или температура, где нет таких вещей, как "точный ответ", и вы все равно должны округлить до точности ваших инструментов в какой-то момент. Я полагаю, что люди, которые программируют компьютер в химической лаборатории, обычно используют поплавки. Но для тех из нас, кто работает в деловом мире, они в значительной степени бесполезны.

В те давние времена, когда я программировал на мэйнфреймах, семейство процессоров IBM 360 имело встроенную поддержку упакованной десятичной арифметики. Они сохраняли строки, в которых каждый байт содержал две десятичные цифры, т.е. первые четыре бита имели значения от 0 до 9 и то же самое для вторых четырех битов, а ЦП имел арифметические функции для управления ими. Почему Intel не может сделать что-то подобное? Тогда Java могла бы добавить «десятичный» тип данных, и нам не понадобился бы весь лишний мусор.

Я, конечно, не говорю об отмене float. Просто добавьте десятичные дроби.

Ну, что касается великих общественных движений, я не стану »

2
ответ дан 27 November 2019 в 22:25
поделиться

В вашем конкретном случае нули удаляются printf. Все начальные нули удаляются компилятором, за исключением начального нуля, который заставляет ваш компилятор рассматривать целое число как восьмеричное. Для 005 и восьмеричное, и десятичное представление одинаковы и не должны вас беспокоить, но тем не менее, он вызывает проблемы, если вы специально не имели в виду восьмеричное представление.

Начальные нули должны иметь дело исключительно со строковым представлением целого числа. Для печати с ведущими нулями используйте «% 03d». Это обеспечит длину поля равную 3.

Как правило, «% d» выводит целое число шириной x символов и дополняет его ведущими пробелами. "% 0 d" будет делать то же самое, но будет дополнять его ведущими нулями.

но, по крайней мере, вывод будет более читабельным.

Например, чтобы округлить результаты до двух десятичных знаков:

System.out.print(String.format(".2f", i) + ","); 
1
ответ дан 27 November 2019 в 22:25
поделиться
Другие вопросы по тегам:

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