Java BigDecimal.rements()存在问题-返回不合理且不准确

Java BigDecimal.rements()存在问题-返回不合理且不准确,java,bigdecimal,Java,Bigdecimal,我正在做一个改变返回计划,这个看似无法解决的问题真的令人沮丧 我使用的是BigDecimal,因此我可以处理精确的结果,但是我的九个BigDecimal.rem余数()方法中有两个返回了不合理和不准确的值(其他七个可以),这使得我的最终结果不准确 例如,如果输入是70.70和100,则输出将是一个额外的5美分硬币 我已经在我的代码中强调了这个问题。非常感谢您的帮助。先谢谢你 import java.math.BigDecimal; 导入java.math.*; 导入java.util.Scann

我正在做一个改变返回计划,这个看似无法解决的问题真的令人沮丧

我使用的是BigDecimal,因此我可以处理精确的结果,但是我的九个BigDecimal.rem余数()方法中有两个返回了不合理和不准确的值(其他七个可以),这使得我的最终结果不准确

例如,如果输入是70.70和100,则输出将是一个额外的5美分硬币

我已经在我的代码中强调了这个问题。非常感谢您的帮助。先谢谢你

import java.math.BigDecimal;
导入java.math.*;
导入java.util.Scanner;
公共类SP010Main{
公共静态void main(字符串[]args){
//宣布纸币和硬币的价值
BigDecimal五十=新的BigDecimal(50.0);
BigDecimal二十=新的BigDecimal(20.0);
BigDecimal十=新的BigDecimal(10.0);
BigDecimal五=新的BigDecimal(5.0);
BigDecimal 2=新的BigDecimal(2.0);
BigDecimal one=新的BigDecimal(1.0);
BigDecimal fiftyC=新的BigDecimal(0.5);
BigDecimal twentyC=新的BigDecimal(0.2);
BigDecimal tenC=新的BigDecimal(0.1);
BigDecimal fiveC=新的BigDecimal(0.05);
//获取成本输入和收到的美元
扫描仪=新的扫描仪(System.in);
系统输出打印(“成本:”);
BigDecimal成本=scanner.nextBigDecimal();
系统输出打印($Received:);
接收到BigDecimal=scanner.nextBigDecimal();
BigDecimal totalC=已收到。减去(成本);
System.out.println(“返回的总更改:+totalC”);
//检查每个值需要多少
BigDecimal fiftyI=(totalC.divide(五十,0,RoundingMode.FLOOR));
totalC=总余数(五十);
BigDecimal twentyI=(totalC.divide(二十,0,RoundingMode.FLOOR));
totalC=总余数(二十);
BigDecimal tenI=(totalC.divide(十,0,RoundingMode.FLOOR));
totalC=总余数(十);
BigDecimal fiveI=(totalC.divide(五,0,RoundingMode.FLOOR));
totalC=总余数(五);
BigDecimal twoI=(totalC.divide(二,0,RoundingMode.FLOOR));
totalC=总余数(两个);
BigDecimal oneI=(totalC.divide(1,0,RoundingMode.FLOOR));
totalC=总余数(一);
BigDecimal fiftyCI=(totalC.divide(fiftyC,0,RoundingMode.FLOOR));
totalC=总余数(五分之一);
//这个问题应该怎么处理----------------------------
//例如,如果输入为70.70和100,
//下面的行将返回0.30
系统输出打印项次(totalC);
// ---------------------------------------------------------------------
BigDecimal twentyCI=(totalC.divide(twentyC,0,RoundingMode.FLOOR));
//问题---------------------------------------------------------
//例如,如果输入为70.70和100,
//以下输出均为0.0999999999999888977697537484345
// 95763683319091796875
totalC=总余数(二十分之一);
系统输出打印项次(totalC);
BigDecimal tenCI=(totalC.divide(tenC,RoundingMode.FLOOR));
totalC=总余数(tenC);
系统输出打印项次(totalC);
//问题结束-------------------------------------------
BigDecimal fiveCI=(totalC.divide(fiveC,0,RoundingMode.FLOOR));
//显示输出
System.out.printf($50:%.0f\n$20:%.0f\n$10:%.0f\n$5:%.0f\n$2:%.0f\n$1:%.0f\n$0.50:%.0f\n$0.20:%.0f\n$0.10:%.0f\n$0.05:%.0f\n”,第五、第二、第二、第五、第二、第五、第二、第五、第二、第二、第五、第二、第二、第三、第五、第三、第五、第三、第五、第三、第三、第五、第五、第五、第三、第五、第三、第三、第五、第五、第五、第五、第;
}
}

即使您正在使用
BigDecimal
对象来获得精确的结果,但在声明表示纸币和硬币的对象时也会引入不精确性:

BigDecimal fifty = new BigDecimal(50.0);
BigDecimal twenty = new BigDecimal(20.0);
// ...
传递给构造函数的值被解释为双精度值,但其中一些值无法以64位双精度格式准确捕获

您应该改用基于
字符串的构造函数:

BigDecimal fifty = new BigDecimal("50.0");
BigDecimal twenty = new BigDecimal("20.0");
// ...
这将为您提供正确的输出:

成本:70.70
收到:100美元
退回的更改总数:29.30
0.30
0.10
0
$50: 0 
$20: 1 
$10: 0 
$5: 1 
$2: 2 
$1: 0 
$0.50: 0 
$0.20: 1 
$0.10: 1 
$0.05: 0 
永远不要使用构造函数。正如javadoc所说:

此构造函数的结果可能有些不可预测

阅读javadoc了解原因


对于您的代码,您有以下选项:

  • 将构造函数用于全部金额,例如
    5
    但不
    0.50

  • 对任何金额使用构造函数,例如
    “5”
    “0.50”

  • 如果需要将输入设置为双精度值,请使用静态方法


问题是什么?是否可以缩短您的示例?您可以使BigDecimal方法返回无理数?真令人印象深刻。