【问题标题】:RoundingMode.DOWN for BigDecimal rounding up insteadRoundingMode.DOWN 用于 BigDecimal 向上舍入
【发布时间】:2019-11-17 09:46:39
【问题描述】:

我正在尝试编写一个程序,该程序以用户使用牛顿法提供的指定精度 (k) 计算整数 (n) 的平方根。该程序运行良好,但我注意到我认为是一个四舍五入的问题。有人可以帮我解决这个问题吗?

例如:

  • 对于输入:n = 81 和 k = 7 / 对于输入:n = 87026 和 k = 11
  • 程序正在打印:9.0000001 / 程序正在打印:295.00169491039
  • 我要打印的内容:9.0000000 / 我要打印的内容:295.00169491038

这是我的代码:

Scanner userInput = new Scanner(System.in);
//print instructions and scan user input
System.out.println("~ This program computes the square root of an integer ~");
System.out.print("\n" + "Enter a non-negative integer [not greater than 1 billion (10^9)] n: ");
int n = userInput.nextInt();
System.out.print("\n" + "Enter a non-negative integer [not greater than 10 thousand (10^4)] k: ");
int k = userInput.nextInt();
userInput.close();
// declaring and converting variables
int p = (k + 1);
BigDecimal num = new BigDecimal(n);
BigDecimal guess = new BigDecimal(n);
BigDecimal newGuess;
BigDecimal sqrt;
// calculating error using int p
BigDecimal error = BigDecimal.ONE.movePointRight(-p);
// calculating guess using int p
BigDecimal diff = BigDecimal.ONE.scaleByPowerOfTen(p);
// newton's loop 
while (diff.compareTo(error) == 1) {
    newGuess = guess.subtract(
        ((guess.multiply(guess)).subtract(num))
        .divide(guess.add(guess), k, RoundingMode.DOWN));
    diff = newGuess.subtract(guess);
    if (diff.signum() == -1) {
        diff = diff.abs();
    }
    guess = newGuess;
}
// printing sqrt to screen    
sqrt = guess;
System.out.println("loop calculated: " + "\n" + sqrt);

【问题讨论】:

    标签: java rounding bigdecimal


    【解决方案1】:

    在循环中,根据牛顿法迭代计算总和,其中 每个 和被四舍五入,对误差有贡献。为了说明这一点,额外输出guess 的初始值和diff 的所有值很有用。对于示例n = 81, k = 7,输出为:

    guess: 81
    diff: 40.0000000
    diff: 19.5121951
    diff: 8.8591124
    diff: 3.1073634
    diff: 0.5070567
    diff: 0.0142611
    diff: 0.0000112
    diff: 0E-7
    loop calculated: 
    9.0000001
    

    如果从guess 中减去所有diff 值,则精确 值为9.0000001,即个别舍入错误导致0.0000001 的偏差。要改变这种行为,可以增加规模,例如加一,k += 1before 循环,并使用 guess = guess.setScale(k - 1, RoundingMode.DOWN);after 循环重置为实际值。那么输出是:

    guess: 81
    diff: 40.00000000
    diff: 19.51219512
    diff: 8.85911242
    diff: 3.10736339
    diff: 0.50705669
    diff: 0.01426108
    diff: 0.00001129
    diff: 0E-8
    loop calculated: 
    9.0000000
    

    现在结果符合预期。可以使用第二个示例n = 87026 , k = 11 验证更改,其输出没有更改:

    guess: 87026
    diff: 43512.50000000000
    diff: 21755.75001149068
    diff: 10876.87510915519
    diff: 5436.43840462864
    diff: 2714.22604199009
    diff: 1349.16761702433
    diff: 659.01405739182
    diff: 300.74946658011
    diff: 107.35187252479
    diff: 18.35523727653
    diff: 0.56993647588
    diff: 0.00055055104
    diff: 5.1E-10
    diff: 0E-11
    loop calculated: 
    295.00169491039
    

    结果中出现模拟错误。修改后的输出为:

    guess: 87026
    diff: 43512.500000000000
    diff: 21755.750011490686
    diff: 10876.875109155187
    diff: 5436.438404628644
    diff: 2714.226041990089
    diff: 1349.167617024336
    diff: 659.014057391816
    diff: 300.749466580112
    diff: 107.351872524786
    diff: 18.355237276533
    diff: 0.569936475871
    diff: 0.000550551041
    diff: 5.13E-10
    diff: 0E-12
    loop calculated: 
    295.00169491038 
    

    符合预期值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多