java - RoundingMode.DOWN 用于 BigDecimal 向上舍入

标签 java rounding bigdecimal

我正在尝试编写一个程序,使用牛顿法计算用户提供的指定精度(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);

最佳答案

在循环中,根据牛顿法迭代计算总和,其中每个被加数都会被舍入并贡献误差。为了说明这一点,额外输出 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

如果从猜测中减去所有差异值,则准确值为9.0000001,即个体舍入误差导致了 0.0000001 的偏差。要改变这种行为,可以增加规模,例如k += 1在循环之前,并使用 guess =guess.setScale(k - 1, RoundingMode.DOWN) 重置为实际值; 循环之后。那么输出是:

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 

符合预期值。

关于java - RoundingMode.DOWN 用于 BigDecimal 向上舍入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58899222/

相关文章:

java - 是数组索引还是赋值先求值?

google-sheets - 如何将单元格格式设置为重量(以克为单位),但删除无关紧要的小数点和位数?

ruby-on-rails - Ruby BigDecimal 圆 : Is this an error?

java - 如何打印格式化的 BigDecimal 值?

java - 从java问题连接到数据库

java - 更高或更低的游戏Java

java - 从 keyTyped 发送火灾事件后未调用 getTableCellRendererComponent

PHP 舍入数字

c++ - int 和 float 中的 super 奇怪的 C++ 黑洞

java - 从 java BigDecimal 转换为 double 时丢失精度