从Java方法返回时,BigDecimal不保持实际值

Bry*_*las 4 java precision bigdecimal

我正在用Java制作货币转换应用程序.其他一些很棒的StackOverflowians给了我建议读取BigDecimal,目的是替换double来解决任何精度问题.

我有两个方法系统; 它从起始货币转换为美元,然后将美元价值转换为目标货币.

请注意,我的转化率存储如下:

// Conversion Rates - START (as of October 30, 2018 @ 3:19 AM)
// Rates obtained from exchange-rates.org

//Convert to United States Dollar rates
private final BigDecimal CAD_TO_USD = new BigDecimal(0.76135);
private final BigDecimal EUR_TO_USD = new BigDecimal(1.1345);
private final BigDecimal YEN_TO_USD = new BigDecimal(0.008853);
// Conversion Rates - END
Run Code Online (Sandbox Code Playgroud)

在我用他们各自的BigDecimals取代我的双打之后 - 我决定测试它并看看它是如何运作的.

我的测试人员类运行以下方法来启动转换过程.

public BigDecimal convert()
{
    BigDecimal value;

    value = convertToUSD(); //Converts the current currency into USD 
    value = convertFromUSD(value);  //Converts the previous USD currency value into the destination currency

    return value;
}
Run Code Online (Sandbox Code Playgroud)

当我输入我的样本变量(将2.78 YEN转换为加元)时,我逐步完成了整个过程,发现一切都在运行,直到我返回一个值.

从前面提到的方法中,convertToUSD()运行并编码如下

private BigDecimal convertToUSD()
{
    switch (fromCurrency)
    {
        case "USD":
            return fromQuantity.multiply(new BigDecimal(1));

        case "CAD":
            return fromQuantity.multiply(CAD_TO_USD);

        case "EUR":
            return fromQuantity.multiply(EUR_TO_USD);

        case "YEN":
            return fromQuantity.multiply(YEN_TO_USD);
    }

    return new BigDecimal(0);
}
Run Code Online (Sandbox Code Playgroud)

ALl值正确传递,它逐步向下到正确的情况("YEN"),变量窗格显示"fromQuantity"BigDecimal的intCompact值为278(这对我来说很有意义)

在此输入图像描述

一旦断点返回到"转换"方法,它就会变得混乱.2.78 * 0.008853 = 0.0246它返回而不是返回-9223372036854775808.

在此输入图像描述

这会导致所有其他计算产生和错误.

我是使用BigDecimal的新手,所以我可能会犯一个完全明显的错误; 但我很高兴学习,所以我向你们寻求建议:)

任何帮助表示赞赏.

Bas*_*que 5

TL;博士

使用String,而不是double文字.

new BigDecimal( "2.78" )           // Pass "2.78" not 2.78
.multiply(
    new BigDecimal( "0.008853" )   // Pass "0.008853" not 0.008853
)
.toString()
Run Code Online (Sandbox Code Playgroud)

0.02461134

不要传递浮点类型

该点BigDecimal类是为了避免固有的不准确的发现浮点技术.诸如float/ Floatdouble/之类的浮点类型Double可以提高执行速度的准确性.相比之下,BigDecimal缓慢但准确.

你的代码:

new BigDecimal( 0.76135 )
new BigDecimal( 1.1345 )
new BigDecimal( 0.008853 )
Run Code Online (Sandbox Code Playgroud)

...传递double原始文字.在编译期间,您键入的文本将0.76135被解析为数字,特别是double(64位浮点值).那时你引入了这种类型固有的不准确性.换句话说,double产生的0.76135可能不再是完全正确的0.76135.

让我们BigDecimal在实例化后立即转储您的实例.

System.out.println( new BigDecimal( 0.76135 ) );    // Passing a `double` primitive.
System.out.println( new BigDecimal( 1.1345 ) );
System.out.println( new BigDecimal( 0.008853 ) );
Run Code Online (Sandbox Code Playgroud)

0.7613499999999999712230192017159424722194671630859375

1.13450000000000006394884621840901672840118408203125

0.0088529999999999997584154698415659368038177490234375

因此,通过创建double数值,您调用了浮点技术,并引入了不准确性.

使用字符串

解决方案?使用字符串,double完全避免使用类型.

在这些输入周围加上一些双引号,.

System.out.println( new BigDecimal( "0.76135" ) );  // Passing a `String` object.
System.out.println( new BigDecimal( "1.1345" ) );
System.out.println( new BigDecimal( "0.008853" ) );
Run Code Online (Sandbox Code Playgroud)

0.76135

1.1345

0.008853

你期待的2.78 * 0.008853 = 0.0246.我们来试试吧.

BigDecimal x = new BigDecimal( "2.78" );
BigDecimal y = new BigDecimal( "0.008853" );
BigDecimal z = x.multiply( y );
System.out.println( x + " * " + y + " = " + z );
Run Code Online (Sandbox Code Playgroud)

2.78*0.008853 = 0.02461134

接下来你应该研究圆角和截断BigDecimal.已经在Stack Overflow上多次覆盖.