如何在 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.

对于BigDecimal.valueOf(double)

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类型floatFloatdoubleDouble均使用floating point technology。浮点技术以牺牲准确性来换取计算中的执行速度。适合某些游戏、图形和 scientific/engineering 目的,但不适合赚钱。

BigDecimal 使用浮点技术。所以计算的执行要慢得多,但结果是准确的。

解决方法:构造BigDecimal时避免浮点数。使用字符串。

new BigDecimal( "123.45" )
new BigDecimal( "0.09" )