Math.pow奇怪的结果

时间:2014-02-02 22:00:10

标签: java android math floating-point ieee

我正在研究抵押贷款计算公式,我从Math.pow()获得了不同的结果,我不知道为什么。

以下是测试设置:

double interestRatePercent = 7;
double monthlyInterestRate = (interestRatePercent / 100) / MONTHS_PER_YEAR;
int numberOfPayments = loanTermInYears * MONTHS_PER_YEAR;

Log.i(TAG, String.format("monthlyInterestRate: %f", monthlyInterestRate));
Log.i(TAG, String.format("numberOfPayments: %d", numberOfPayments));
Log.i(TAG, "  ");

Log.i(TAG, "Hardcoded result:");
double hardcodedResult = Math.pow(1.0 + 0.005833, numberOfPayments);
Log.i(TAG, String.format("(1 + 0.005833)^360 = %f", hardcodedResult));
Log.i(TAG, "  ");

Log.i(TAG, "Parameterized result:");
double paramResult = Math.pow(1.0 + monthlyInterestRate, numberOfPayments);
Log.i(TAG, String.format("(1 + %f)^%d = %f", monthlyInterestRate, numberOfPayments, paramResult));
Log.i(TAG, "  ");

Log.i(TAG, "BigDecimal result:");
BigDecimal bigResult = BigDecimal.valueOf(1.0 + monthlyInterestRate);
bigResult = bigResult.pow(numberOfPayments);
Log.i(TAG, String.format("(1 + %f)^%d = %f", monthlyInterestRate, numberOfPayments, bigResult));
Log.i(TAG, "  ");
Log.i(TAG, "  ");

以下是测试结果:

monthlyInterestRate: 0.005833
numberOfPayments: 360

Hardcoded result:
(1 + 0.005833)^360 = 8.115529

Parameterized result:
(1 + 0.005833)^360 = 8.116497

BigDecimal result:
(1 + 0.005833)^360 = 8.116497

只有硬编码的结果才是正确的。 Math.pow和BigDecimal.pow结果都很糟糕。

有什么想法吗?

3 个答案:

答案 0 :(得分:6)

7/100/12约为0.00583333333,而不是0.005833。使用%f时,默认情况下只能看到小数点后的6位数。

答案 1 :(得分:3)

BigDecimal bigResult = BigDecimal.valueOf(1.0 + monthlyInterestRate);

当您创建BigDecimal时,您将失去精确度,因为1.0 + monthlyInterestRate将失去精确度。要获得更好的精确度,请为1.0创建BigDecimal,然后使用add()方法将其添加到值为0.005833的另一个BigDecimal。然后使用BigDecimal pow()函数。

换句话说,从更简单的BigDecimal而不是BigDecimalsint类型构建double

答案 2 :(得分:1)

差异是由于在硬编码结果计算中舍入0.002533333333333333599324266316443754476495087146759033203125(monthlyInterestRate的实际值)为0.005833。为方便起见,我修改了程序以使用System.out.println。我更改了monthlyInterestRate的输出以准确打印它,然后在硬编码计算中使用该值。输出是:

monthlyInterestRate: 0.005833333333333333599324266316443754476495087146759033203125
numberOfPayments: 360

Hardcoded result:
(1 + 0.005833333333333333599324266316443754476495087146759033203125)^360 = 8.116497

Parameterized result:
(1 + 0.005833)^360 = 8.116497

BigDecimal result:
(1 + 0.005833)^360 = 8.116497

以下是修改后的程序:

import java.math.BigDecimal;

public class Test {
    public static void main(String[] args) {
        double interestRatePercent = 7;
        int MONTHS_PER_YEAR = 12;
        int loanTermInYears = 30;
        double monthlyInterestRate = (interestRatePercent / 100)
                / MONTHS_PER_YEAR;
        int numberOfPayments = loanTermInYears * MONTHS_PER_YEAR;

        // System.out.println(String.format("monthlyInterestRate: %f",
        // monthlyInterestRate));
        System.out.println("monthlyInterestRate: "
                + new BigDecimal(monthlyInterestRate));
        System.out.println(String.format("numberOfPayments: %d",
                numberOfPayments));
        System.out.println("  ");

        System.out.println("Hardcoded result:");
        double hardcodedResult = Math
                .pow(1.0 + 0.005833333333333333599324266316443754476495087146759033203125,
                        numberOfPayments);
        System.out
                .println(String
                        .format("(1 + 0.005833333333333333599324266316443754476495087146759033203125)^360 = %f",
                                hardcodedResult));
        System.out.println("  ");

        System.out.println("Parameterized result:");
        double paramResult = Math.pow(1.0 + monthlyInterestRate,
                numberOfPayments);
        System.out.println(String.format("(1 + %f)^%d = %f",
                monthlyInterestRate, numberOfPayments, paramResult));
        System.out.println("  ");

        System.out.println("BigDecimal result:");
        BigDecimal bigResult = BigDecimal.valueOf(1.0 + monthlyInterestRate);
        bigResult = bigResult.pow(numberOfPayments);
        System.out.println(String.format("(1 + %f)^%d = %f",
                monthlyInterestRate, numberOfPayments, bigResult));
        System.out.println("  ");
        System.out.println("  ");
    }
}