public class doublePrecision {
public static void main(String[] args) {
double total = 0;
total += 5.6;
total += 5.8;
System.out.println(total);
}
}
Приведенный выше код печатает:
11.399999999999
Как мне заставить это просто напечатать (или быть в состоянии использовать это как) 11.4?
java
floating-point
double
precision
Deinumite
источник
источник
Ответы:
Как уже упоминали другие, вы, вероятно, захотите использовать
BigDecimal
класс, если вы хотите иметь точное представление 11.4.Теперь небольшое объяснение, почему это происходит:
Эти
float
иdouble
примитивные типы в Java являются плавающей точкой число, где число хранится в виде двоичного представления фракции и экспоненты.Более конкретно, значение с плавающей запятой двойной точности, такое как
double
тип, является 64-битным значением, где:Эти части объединяются для создания
double
представления значения.(Источник: Википедия: Двойная точность )
Подробное описание того, как обрабатываются значения с плавающей запятой в Java, см. В разделе 4.2.3. Типы, форматы и значения с плавающей запятой. Спецификации языка Java.
В
byte
,char
,int
,long
типов с фиксированной точкой число, которые являются точными представлениями чисел. В отличие от чисел с фиксированной запятой, числа с плавающей запятой в некоторых случаях (можно предположить «большую часть времени») не смогут вернуть точное представление числа. Это причина, почему вы в конечном итоге11.399999999999
в результате5.6 + 5.8
.Когда требуется точное значение, например, 1,5 или 150,1005, вы захотите использовать один из типов с фиксированной запятой, который сможет точно представлять число.
Как уже упоминалось несколько раз, в Java есть
BigDecimal
класс, который будет обрабатывать очень большие числа и очень маленькие числа.Из Java API Reference для
BigDecimal
класса:Было много вопросов о переполнении стека, касающихся вопроса о числах с плавающей запятой и его точности. Вот список связанных вопросов, которые могут представлять интерес:
Если вы действительно хотите перейти к мельчайшим деталям чисел с плавающей запятой, взгляните на то, что каждый ученый-компьютерщик должен знать об арифметике с плавающей запятой .
источник
BigDecimal
это намного медленнее, чемdouble
в этом случае, это не нужно, поскольку double имеет 15 десятичных знаков точности, вам просто нужно округлить.Например, когда вы вводите двойное число,
33.33333333333333
полученное значение фактически является ближайшим представимым значением двойной точности, а именно:Разделив это на 100, получим:
который также не может быть представлен как число с двойной точностью, поэтому он снова округляется до ближайшего представимого значения, которое точно:
Когда вы выводите это значение, оно снова округляется до 17 десятичных цифр, давая:
источник
Если вы просто хотите обрабатывать значения как дроби, вы можете создать класс Fraction, который содержит поле числителя и знаменателя.
Написать методы для сложения, вычитания, умножения и деления, а также метод toDouble. Таким образом, вы можете избежать поплавков во время расчетов.
РЕДАКТИРОВАТЬ: Быстрое внедрение,
источник
numerator
иdenominator
должно бытьint
? Зачем вам нужна точность с плавающей точкой?Заметьте, что у вас возникнет та же проблема, если вы используете десятичную арифметику с ограниченной точностью и хотите иметь дело с 1/3: 0,333333333 * 3 - это 0,9999999999, а не 1,00000000.
К сожалению, 5.6, 5.8 и 11.4 просто не являются круглыми числами в двоичном формате, потому что они включают пятые. Таким образом, их представление с плавающей точкой не является точным, так же как 0,3333 не совсем 1/3.
Если все числа, которые вы используете, являются неповторяющимися десятичными числами, и вы хотите получить точные результаты, используйте BigDecimal. Или, как говорили другие, если ваши значения похожи на деньги в том смысле, что все они кратны 0,01, или 0,001, или что-то еще, умножьте все на фиксированную степень 10 и используйте int или long (сложение и вычитание тривиально: следите за умножением).
Тем не менее, если вы довольны двоичными данными для расчета, но хотите просто распечатать их в более дружественном формате, попробуйте
java.util.Formatter
илиString.format
. В строке формата укажите точность, меньшую полной точности в два раза. Например, для 10 значащих цифр 11,399999999999 равно 11,4, поэтому результат будет почти таким же точным и более понятным для человека в тех случаях, когда двоичный результат очень близок к значению, требующему только несколько десятичных знаков.Точность задания зависит немного от того, сколько математики вы выполнили со своими числами - в общем, чем больше вы делаете, тем больше ошибок накапливается, но некоторые алгоритмы накапливают его намного быстрее, чем другие (их называют «нестабильными», так как в отличие от "стабильных" в отношении ошибок округления). Если все, что вы делаете - это добавляете несколько значений, то я предполагаю, что отбрасывание только одного десятичного знака точности решит проблему. Эксперимент.
источник
Возможно, вы захотите изучить использование java-класса java.math.BigDecimal, если вам действительно нужна точность математики. Вот хорошая статья от Oracle / Sun по делу BigDecimal . Хотя вы никогда не можете представить 1/3, как кто-то упоминал, вы можете иметь право решать , как именно вы хотите точный результат будет. setScale () твой друг .. :)
Хорошо, потому что у меня сейчас слишком много времени, вот пример кода, который относится к вашему вопросу:
и чтобы подключить мой новый любимый язык, Groovy, вот еще один пример того же:
источник
Уверен, вы могли бы превратить это в пример из трех строк. :)
Если вам нужна точная точность, используйте BigDecimal. В противном случае вы можете использовать целые числа, умноженные на 10 ^, с любой точностью, которую вы хотите.
источник
Как отметили другие, не все десятичные значения могут быть представлены в двоичном виде, поскольку десятичное число основано на степенях 10, а двоичное - на степенях двух.
Если точность имеет значение, используйте BigDecimal, но если вы просто хотите дружественный вывод:
Дам тебе:
источник
Вы сталкиваетесь с ограничением точности типа double.
Java.Math имеет некоторые арифметические средства произвольной точности.
источник
Вы не можете, потому что 7.3 не имеет конечного представления в двоичном формате. Ближайшее, что вы можете получить, это 2054767329987789/2 ** 48 = 7,3 + 1/1407374883553280.
Взгляните на http://docs.python.org/tutorial/floatingpoint.html для дальнейшего объяснения. (Он находится на сайте Python, но у Java и C ++ одна и та же «проблема».)
Решение зависит от того, что именно является вашей проблемой:
источник
источник
Используйте java.math.BigDecimal
Двойные числа - это двоичные дроби внутри, поэтому они иногда не могут представлять десятичные дроби с точностью до десятичной дроби.
источник
Умножьте все на 100 и сохраните в длинных центах.
источник
Компьютеры хранят числа в двоичном виде и не могут точно представлять числа, такие как 33.333333333 или 100.0. Это одна из хитрых вещей с использованием двойников. Вам придется просто округлить ответ, прежде чем показывать его пользователю. К счастью, в большинстве приложений вам не нужно столько десятичных знаков.
источник
Числа с плавающей запятой отличаются от действительных чисел тем, что для любого заданного числа с плавающей запятой существует следующий более высокий номер с плавающей запятой. То же, что целые числа. Там нет целого числа между 1 и 2.
Там нет никакого способа представить 1/3 как поплавок. Под ним есть поплавок, над ним есть поплавок, и между ними есть определенное расстояние. И 1/3 находится в этом пространстве.
Apfloat для Java утверждает, что работает с числами с плавающей запятой произвольной точности, но я никогда не использовал его. Наверное, стоит посмотреть. http://www.apfloat.org/apfloat_java/
Подобный вопрос был задан здесь до библиотеки высокой точности Java с плавающей точкой
источник
Двойные числа - это приблизительные значения десятичных чисел в вашем исходном коде Java. Вы видите последствия несоответствия между double (который является двоичным значением) и вашим источником (который является десятичным).
Java производит самое близкое двоичное приближение. Вы можете использовать java.text.DecimalFormat для отображения лучшего десятичного значения.
источник
Используйте BigDecimal. Он даже позволяет вам задать правила округления (например, ROUND_HALF_EVEN, которые минимизируют статистическую ошибку, округляя до четного соседа, если оба имеют одинаковое расстояние; то есть оба с 1,5 и 2,5 округляют до 2).
источник
Краткий ответ: всегда используйте BigDecimal и убедитесь, что вы используете конструктор с аргументом String , а не с двойным.
Возвращаясь к вашему примеру, следующий код напечатает 11.4, как вы пожелаете.
источник
Посмотрите BigDecimal, он решает проблемы, связанные с такой арифметикой с плавающей точкой.
Новый вызов будет выглядеть так:
Используйте setScale (), чтобы установить число десятичных знаков, которые будут использоваться.
источник
Почему бы не использовать метод round () из класса Math?
источник
Если у вас нет другого выбора, кроме использования двойных значений, можете использовать приведенный ниже код.
источник
Не тратьте свои силы, используя BigDecimal. В 99,9999% случаев вам это не нужно. Тип java double является приблизительным, но почти во всех случаях он достаточно точен. Имейте в виду, что у вас есть ошибка в 14-й значащей цифре.Это действительно незначительно!
Чтобы получить хороший результат, используйте:
источник