Функция Math.Pow () в Java, возвращающая запутанные результаты - PullRequest
0 голосов
/ 25 января 2011

Я работаю с функцией Math.pow () и имею следующий код:

double monthlyRate = (0.7d / 12);
int loanLength = 3;

double powerTest = Math.pow(1.00583, 36);
double powerResult = Math.pow((1 + monthlyRate),(loanLength * 12));

При запуске через отладчик значения становятся

powerTest => 1.2327785029794363
powerResult => 7.698552870922063

Первый - правильный. Я вошел в функцию Math.pow в обеих строках назначения. Для powerTest, параметры для Math.pow double a => 1.00583 двойной b => 36,0

Для powerResult они double a => 1.0058333333333333 двойной b => 36,0

Я знаю, что это проблема с тем, как машина выполняет вычисления с плавающей запятой, я просто не знаю, как это исправить Я попытался сделать следующее до вычисления с плохими результатами:

monthlyRate = Math.round(monthlyRate * 1000) / 1000;

Ответы [ 7 ]

9 голосов
/ 25 января 2011

1 + monthlyRate равно 1.0583..., а не 1.00583.

3 голосов
/ 25 января 2011

Ваше выражение 0,7d / 12 = 0,0583, в выражении powerTest вы используете 0,00583.

2 голосов
/ 25 января 2011

Очевидно, что такая большая разница в результатах (1.23 ... и 7.70) не связана с тем, как кодируются поплавки, но больше, чем вы допустили ошибку, где 1 + 0.7 / 12 = 1.0583 отличается от 1.00583 ;-).

2 голосов
/ 25 января 2011

Я думаю, что часть проблемы в том, что 0.7/12 ~ 0.058333 и 1.0583 > 1.00583.Бьюсь об заклад, это истинный источник вашего несоответствия, корректировки с плавающей запятой имеют мало общего с этим.

1 голос
/ 25 января 2011

В Java вы можете использовать BigDecimal для выполнения операций с деньгами, получая точные числа: это Sun / Oracle рекомендуемый способ для хранения чисел денег.

// I'm using Strings for most accuracy

BigDecimal monthlyRate = new BigDecimal("0.7").divide(new BigDecimal(12));
int loanLength = 3;

BigDecimal powerTest = new BigDecimal("1.00583").pow(36);
BigDecimal powerResult = BigDecimal.ONE.add(monthlyRate).pow(loanLength * 12);
1 голос
/ 25 января 2011
Math.round(monthlyRate * 1000) / 1000.0;

Вы использовали целочисленное деление.

0 голосов
/ 25 января 2011
monthlyRate = ((double)Math.round(monthlyRate * 1000)) / 1000;
...