Я попытаюсь объяснить вам статическую вещь. Прежде всего статические переменные не принадлежат ни одному конкретному экземпляру класса. Они распознаются с именем класса. Статические методы снова не относятся к какому-либо конкретному экземпляру. Они могут получить доступ только к статическим переменным. Представьте, что вы вызываете MyClass.myMethod (), а myMethod - это статический метод. Если вы используете нестатические переменные внутри метода, как, черт возьми, он знает, какие переменные использовать? Вот почему вы можете использовать из статических методов только статические переменные. Повторяю, они НЕ принадлежат ни одному конкретному экземпляру.
Используйте BigDecimal
вместо float
/ double
. Существует множество чисел, которые не могут быть представлены как двоичная с плавающей запятой (например, 0.1
). Таким образом, вы либо должны всегда округлять результат до известной точности, либо использовать BigDecimal
.
Для получения дополнительной информации см. http://en.wikipedia.org/wiki/Floating_point .
BigDecimal
, так как это уловит большинство распространенных ошибок. Если все слишком медленно, им нужно больше узнать и найти способы оптимизации своих проблем. Преждевременная оптимизация - корень всего зла - Д.Е. Кнут.
– Aaron Digulla
18 August 2016 в 14:56
Сегодня я столкнулся с этой проблемой и не мог использовать рефакторинг для BigDecimal, потому что проект действительно огромный.
Обратите внимание, что вызов result.doubleValue () возвращает 5623.22998046875
Но вызов doubleResult.doubleValue () правильно возвращает 5623.23
Но я не совсем уверен, правильно ли это решение.
Это связано с контрактом Float.toString(float)
, , который частично говорит:
Сколько цифр должно быть напечатано для дробной части [& hellip;]? Должна быть хотя бы одна цифра для представления дробной части, а кроме нее столько, сколько всего, больше цифр, которые необходимы, чтобы однозначно различать значение аргумента от смежных значений типа float. That Предположим, что x - точное математическое значение, представленное десятичным представлением, созданным этим методом, для конечного ненулевого аргумента f. Тогда f должно быть значением float, ближайшим к x; или, если два значения float одинаково близки к x, то f должен быть одним из них, а младший значащий бит значения f должен быть 0.
blockquote>
Я нашел следующее решение:
public static Double getFloatAsDouble(Float fValue) {
return Double.valueOf(fValue.toString());
}
Если вы используете float и double вместо Float и Двойной используйте следующее:
public static double getFloatAsDouble(float value) {
return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}
Я считаю, что преобразование в двоичное представление проще для понимания этой проблемы.
float f = 0.27f;
double d2 = (double) f;
double d3 = 0.27d;
System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));
Вы можете видеть, что float расширяется до double, добавляя 0s к концу, но двойное представление 0.27 является «более точным», следовательно, проблема.
111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000
Для информации это относится к пункту 48 - Избегайте float и double, когда требуются точные значения, из Effective Java 2nd edition от Джошуа Блоха. Эта книга - варенье, наполненное хорошими вещами, и, безусловно, стоит посмотреть.
Поплавки по своей природе неточны и всегда имеют аккуратные округлые «проблемы». Если точность важна, вы можете рассмотреть возможность рефакторинга приложения для использования Decimal или BigDecimal.
Да, поплавки вычисляются быстрее, чем десятичные числа из-за поддержки процессора. Однако вы хотите быстро или точно?
Это работает?
float flt = 145.664454;
Double dbl = 0.0;
dbl += flt;