如何在 java 中将美元金额转换为美分?
How to convert dollar amount to cents in java?
我有以下程序(取自 SO link )将美元转换为美分。但是,输出并不符合我的预期。
当前输出:
12345
8
预期输出:
12345
9
Main.java
public class Main {
private static final BigDecimal x100 = new BigDecimal(100);
static List<BigDecimal> nums = new ArrayList<>();
static BigDecimal a = new BigDecimal(123.45);
static BigDecimal b = new BigDecimal(0.09);
public static void main(String[] args) {
nums.add(a);
nums.add(b);
for (BigDecimal usd : nums) {
BigDecimal rounded = usd.setScale(2, BigDecimal.ROUND_DOWN);
BigDecimal bigDecimalInCents = rounded.multiply(x100);
int cents = bigDecimalInCents.intValueExact();
System.out.println(cents);
}
}
}
你的问题是双打不能代表所有的值。 9/100
,例如,只能近似。尝试 System.out.println(new BigDecimal(0.09))
。你应该得到 0.0899999999999999966693309261245303787291049957275390625
。因此,您将其四舍五入为 0.08,然后乘以 100。
尝试new BigDecimal(String.valueOf(0.09))
编辑:
更好的方案是使用BigDecimal.valueOf(0.09)
,等价于
来自 BigDecimal(double) 的 javadoc:
Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value.
...
When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.
Translates a double into a BigDecimal, using the double's canonical string representation provided by the Double.toString(double) method.
Note: This is generally the preferred way to convert a double (or float) into a BigDecimal, as the value returned is equal to that resulting from constructing a BigDecimal from the result of using Double.toString(double).
tl;博士
使用字符串,而不是数字文字。
new BigDecimal( "123.45" )
避免浮点数
您在构造 BigDecimal
时隐式地将 double
类型基元引入代码。
new BigDecimal( 123.45 ) // <-- Passing `double` primitive
new BigDecimal( 0.09 )
当您认为自己超过了 123.45
时,您实际上超过了 123.4500000000000028421709430404007434844970703125
。而不是 0.09
你传递的是更像 0.0899999999999999966693309261245303787291049957275390625
的东西。
您违背了将 BigDecimal 与货币一起使用的目的,即避免 inherent inaccuracy of floating-point 类型确定其小数部分。
Java类型float
、Float
、double
、Double
均使用floating point technology。浮点技术以牺牲准确性来换取计算中的执行速度。适合某些游戏、图形和 scientific/engineering 目的,但不适合赚钱。
BigDecimal
不 使用浮点技术。所以计算的执行要慢得多,但结果是准确的。
解决方法:构造BigDecimal
时避免浮点数。使用字符串。
new BigDecimal( "123.45" )
new BigDecimal( "0.09" )
我有以下程序(取自 SO link
当前输出:
12345
8
预期输出:
12345
9
Main.java
public class Main {
private static final BigDecimal x100 = new BigDecimal(100);
static List<BigDecimal> nums = new ArrayList<>();
static BigDecimal a = new BigDecimal(123.45);
static BigDecimal b = new BigDecimal(0.09);
public static void main(String[] args) {
nums.add(a);
nums.add(b);
for (BigDecimal usd : nums) {
BigDecimal rounded = usd.setScale(2, BigDecimal.ROUND_DOWN);
BigDecimal bigDecimalInCents = rounded.multiply(x100);
int cents = bigDecimalInCents.intValueExact();
System.out.println(cents);
}
}
}
你的问题是双打不能代表所有的值。 9/100
,例如,只能近似。尝试 System.out.println(new BigDecimal(0.09))
。你应该得到 0.0899999999999999966693309261245303787291049957275390625
。因此,您将其四舍五入为 0.08,然后乘以 100。
尝试new BigDecimal(String.valueOf(0.09))
编辑:
更好的方案是使用BigDecimal.valueOf(0.09)
,等价于
来自 BigDecimal(double) 的 javadoc:
Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value.
...
When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.
Translates a double into a BigDecimal, using the double's canonical string representation provided by the Double.toString(double) method.
Note: This is generally the preferred way to convert a double (or float) into a BigDecimal, as the value returned is equal to that resulting from constructing a BigDecimal from the result of using Double.toString(double).
tl;博士
使用字符串,而不是数字文字。
new BigDecimal( "123.45" )
避免浮点数
您在构造 BigDecimal
时隐式地将 double
类型基元引入代码。
new BigDecimal( 123.45 ) // <-- Passing `double` primitive
new BigDecimal( 0.09 )
当您认为自己超过了 123.45
时,您实际上超过了 123.4500000000000028421709430404007434844970703125
。而不是 0.09
你传递的是更像 0.0899999999999999966693309261245303787291049957275390625
的东西。
您违背了将 BigDecimal 与货币一起使用的目的,即避免 inherent inaccuracy of floating-point 类型确定其小数部分。
Java类型float
、Float
、double
、Double
均使用floating point technology。浮点技术以牺牲准确性来换取计算中的执行速度。适合某些游戏、图形和 scientific/engineering 目的,但不适合赚钱。
BigDecimal
不 使用浮点技术。所以计算的执行要慢得多,但结果是准确的。
解决方法:构造BigDecimal
时避免浮点数。使用字符串。
new BigDecimal( "123.45" )
new BigDecimal( "0.09" )