如何在 java 中将美元金额转换为美分?



我有以下程序(取自SO链接在java中将美元(大十进制)转换为美分(整数)的最佳方法是什么?但是,输出并不符合我的预期。

电流输出:

12345
8

预期输出:

12345
9

主.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);
}
}
}

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 与货币一起使用的真正目的,即避免浮点类型在确定其小数部分时固有的不准确性

Java类型floatFloatdoubleDouble都使用浮点技术。浮点技术在计算中牺牲了准确性和执行速度。适用于某些游戏、图形和科学/工程目的,但对金钱不利。

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

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

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

您的问题是双精度不能代表所有值。 例如,9/100只能是近似的。试试System.out.println(new BigDecimal(0.09)).你应该得到0.0899999999999999966693309261245303787291049957275390625.因此,您将其四舍五入为 0.08,然后乘以 100。

试试new BigDecimal(String.valueOf(0.09))

编辑:更好的解决方案是使用BigDecimal.valueOf(0.09),这是等效的。

来自 javadoc for BigDecimal(double):

将双精度转换为 BigDecimal ,后者是双精度的二进制浮点值的精确十进制表示形式。
...
当必须将双精度值用作 BigDecimal 的源时,请注意,此构造函数提供了精确的转换;它给出的结果与使用 Double.toString(double) 方法将双精度转换为字符串,然后使用 BigDecimal(String) 构造函数的结果不同。若要获得该结果,请使用静态值Of(double)方法。

对于 BigDecimal.valueOf(double):

使用 Double.toString(double) 方法提供的双精度的规范字符串表示形式将双精度转换为 BigDecimal。

注意:这通常是将双精度(或浮点数)转换为 BigDecimal 的首选方法,因为返回的值等于使用 Double.toString(double) 的结果构造 BigDecimal 产生的值。

最新更新