Java BigDecimal.remainder() 的问题 - 不合理且不准确 returns
Problem with Java BigDecimal.remainder() - irrational and inaccurate returns
我正在修改return程序,这个看似无法解决的问题实在令人沮丧。
我正在使用 BigDecimal,因此我可以使用精确的结果,但是我的九个 BigDecimal.remainder() 方法中有两个是 returning 非理性和不准确的值(其他七个工作正常),这使我的最终结果不准确。
例如,如果输入为 70.70 和 100,则输出将是一个额外的 5 美分硬币。
我已经突出显示了我的代码中的问题。非常感谢任何帮助。提前谢谢你。
import java.math.BigDecimal;
import java.math.*;
import java.util.Scanner;
public class SP010Main {
public static void main(String[] args) {
// Declaring the values of notes and coins
BigDecimal fifty = new BigDecimal(50.0);
BigDecimal twenty = new BigDecimal(20.0);
BigDecimal ten = new BigDecimal(10.0);
BigDecimal five = new BigDecimal(5.0);
BigDecimal two = new BigDecimal(2.0);
BigDecimal one = new BigDecimal(1.0);
BigDecimal fiftyC = new BigDecimal(0.5);
BigDecimal twentyC = new BigDecimal(0.2);
BigDecimal tenC = new BigDecimal(0.1);
BigDecimal fiveC = new BigDecimal(0.05);
// Getting input of cost and $ received
Scanner scanner = new Scanner(System.in);
System.out.print("Cost: ");
BigDecimal cost = scanner.nextBigDecimal();
System.out.print("$ Received: ");
BigDecimal received = scanner.nextBigDecimal();
BigDecimal totalC = received.subtract(cost);
System.out.println("Total change returned: " + totalC);
// Checking how many of each value is needed
BigDecimal fiftyI = (totalC.divide(fifty, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(fifty);
BigDecimal twentyI = (totalC.divide(twenty, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(twenty);
BigDecimal tenI = (totalC.divide(ten, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(ten);
BigDecimal fiveI = (totalC.divide(five, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(five);
BigDecimal twoI = (totalC.divide(two, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(two);
BigDecimal oneI = (totalC.divide(one, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(one);
BigDecimal fiftyCI = (totalC.divide(fiftyC, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(fiftyC);
// What should be happening with the problem----------------------------
// E.g. if input is 70.70 and 100,
// Following line will return 0.30
System.out.println(totalC);
// ---------------------------------------------------------------------
BigDecimal twentyCI = (totalC.divide(twentyC, 0, RoundingMode.FLOOR));
// The problem ---------------------------------------------------------
// E.g. if input is 70.70 and 100,
// Following outputs will both be 0.0999999999999999888977697537484345
// 95763683319091796875
totalC = totalC.remainder(twentyC);
System.out.println(totalC);
BigDecimal tenCI = (totalC.divide(tenC, RoundingMode.FLOOR));
totalC = totalC.remainder(tenC);
System.out.println(totalC);
// End of the problem --------------------------------------------------
BigDecimal fiveCI = (totalC.divide(fiveC, 0, RoundingMode.FLOOR));
// Display output
System.out.printf(": %.0f \n: %.0f \n: %.0f \n: %.0f \n: %.0f \n: %.0f \n[=13=].50: %.0f \n[=13=].20: %.0f \n[=13=].10: %.0f \n[=13=].05: %.0f \n",fiftyI, twentyI, tenI, fiveI, twoI, oneI, fiftyCI, twentyCI, tenCI, fiveCI);
}
}
即使您使用 BigDecimal
对象来获得精确的结果,您在声明代表钞票和硬币的对象时也会引入不精确:
BigDecimal fifty = new BigDecimal(50.0);
BigDecimal twenty = new BigDecimal(20.0);
// ...
传递给构造函数的值被解释为双精度值,但其中一些值无法以 64 位双精度格式准确捕获。
您应该改用基于 String
的构造函数:
BigDecimal fifty = new BigDecimal("50.0");
BigDecimal twenty = new BigDecimal("20.0");
// ...
这会给你正确的输出:
Cost: 70.70
$ Received: 100
Total change returned: 29.30
0.30
0.10
0.00
: 0
: 1
: 0
: 1
: 2
: 0
[=12=].50: 0
[=12=].20: 1
[=12=].10: 1
[=12=].05: 0
永远不要使用 BigDecimal(double)
构造函数。正如 javadoc 所说:
The results of this constructor can be somewhat unpredictable.
阅读 javadoc 了解原因。
对于您的代码,您有以下选项:
对整数使用 BigDecimal(int)
构造函数,例如5
但不是 0.50
对任意数量使用 BigDecimal(String)
构造函数,例如"5"
和 "0.50"
如果需要输入为 double
值,请使用 BigDecimal.valueOf(double)
静态方法。
我正在修改return程序,这个看似无法解决的问题实在令人沮丧。
我正在使用 BigDecimal,因此我可以使用精确的结果,但是我的九个 BigDecimal.remainder() 方法中有两个是 returning 非理性和不准确的值(其他七个工作正常),这使我的最终结果不准确。
例如,如果输入为 70.70 和 100,则输出将是一个额外的 5 美分硬币。
我已经突出显示了我的代码中的问题。非常感谢任何帮助。提前谢谢你。
import java.math.BigDecimal;
import java.math.*;
import java.util.Scanner;
public class SP010Main {
public static void main(String[] args) {
// Declaring the values of notes and coins
BigDecimal fifty = new BigDecimal(50.0);
BigDecimal twenty = new BigDecimal(20.0);
BigDecimal ten = new BigDecimal(10.0);
BigDecimal five = new BigDecimal(5.0);
BigDecimal two = new BigDecimal(2.0);
BigDecimal one = new BigDecimal(1.0);
BigDecimal fiftyC = new BigDecimal(0.5);
BigDecimal twentyC = new BigDecimal(0.2);
BigDecimal tenC = new BigDecimal(0.1);
BigDecimal fiveC = new BigDecimal(0.05);
// Getting input of cost and $ received
Scanner scanner = new Scanner(System.in);
System.out.print("Cost: ");
BigDecimal cost = scanner.nextBigDecimal();
System.out.print("$ Received: ");
BigDecimal received = scanner.nextBigDecimal();
BigDecimal totalC = received.subtract(cost);
System.out.println("Total change returned: " + totalC);
// Checking how many of each value is needed
BigDecimal fiftyI = (totalC.divide(fifty, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(fifty);
BigDecimal twentyI = (totalC.divide(twenty, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(twenty);
BigDecimal tenI = (totalC.divide(ten, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(ten);
BigDecimal fiveI = (totalC.divide(five, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(five);
BigDecimal twoI = (totalC.divide(two, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(two);
BigDecimal oneI = (totalC.divide(one, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(one);
BigDecimal fiftyCI = (totalC.divide(fiftyC, 0, RoundingMode.FLOOR));
totalC = totalC.remainder(fiftyC);
// What should be happening with the problem----------------------------
// E.g. if input is 70.70 and 100,
// Following line will return 0.30
System.out.println(totalC);
// ---------------------------------------------------------------------
BigDecimal twentyCI = (totalC.divide(twentyC, 0, RoundingMode.FLOOR));
// The problem ---------------------------------------------------------
// E.g. if input is 70.70 and 100,
// Following outputs will both be 0.0999999999999999888977697537484345
// 95763683319091796875
totalC = totalC.remainder(twentyC);
System.out.println(totalC);
BigDecimal tenCI = (totalC.divide(tenC, RoundingMode.FLOOR));
totalC = totalC.remainder(tenC);
System.out.println(totalC);
// End of the problem --------------------------------------------------
BigDecimal fiveCI = (totalC.divide(fiveC, 0, RoundingMode.FLOOR));
// Display output
System.out.printf(": %.0f \n: %.0f \n: %.0f \n: %.0f \n: %.0f \n: %.0f \n[=13=].50: %.0f \n[=13=].20: %.0f \n[=13=].10: %.0f \n[=13=].05: %.0f \n",fiftyI, twentyI, tenI, fiveI, twoI, oneI, fiftyCI, twentyCI, tenCI, fiveCI);
}
}
即使您使用 BigDecimal
对象来获得精确的结果,您在声明代表钞票和硬币的对象时也会引入不精确:
BigDecimal fifty = new BigDecimal(50.0);
BigDecimal twenty = new BigDecimal(20.0);
// ...
传递给构造函数的值被解释为双精度值,但其中一些值无法以 64 位双精度格式准确捕获。
您应该改用基于 String
的构造函数:
BigDecimal fifty = new BigDecimal("50.0");
BigDecimal twenty = new BigDecimal("20.0");
// ...
这会给你正确的输出:
Cost: 70.70
$ Received: 100
Total change returned: 29.30
0.30
0.10
0.00
: 0
: 1
: 0
: 1
: 2
: 0
[=12=].50: 0
[=12=].20: 1
[=12=].10: 1
[=12=].05: 0
永远不要使用 BigDecimal(double)
构造函数。正如 javadoc 所说:
The results of this constructor can be somewhat unpredictable.
阅读 javadoc 了解原因。
对于您的代码,您有以下选项:
对整数使用
BigDecimal(int)
构造函数,例如5
但不是0.50
对任意数量使用
BigDecimal(String)
构造函数,例如"5"
和"0.50"
如果需要输入为
double
值,请使用BigDecimal.valueOf(double)
静态方法。