从 Java 方法返回时,BigDecimal 不保留实际值
BigDecimal not keeping actual value when being returned from Java method
我正在 Java 制作货币转换应用程序。其他一些出色的 Whosebug 开发人员建议我阅读 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
在我用各自的 BigDecimals 替换我的双打之后 - 我决定测试它并看看它是如何工作的。
我的测试人员 class 运行使用以下方法启动转换过程。
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;
}
当我输入示例变量(将 2.78 日元转换为加元)时,我逐步完成了整个过程,发现一切正常,直到我 return 一个值。
由前面提到的方法,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);
}
所有值均已正确传递,它向下逐步找到正确的大小写 ("YEN"),并且变量窗格显示 "fromQuantity" BigDecimal 的 intCompact 值为 278(这对我来说很有意义)
一旦断点 return 回到 "convert" 方法,它就会变得一团糟。而不是 returning 2.78 * 0.008853 = 0.0246
,它 returns -9223372036854775808
.
这会导致所有其他计算产生错误。
我刚开始使用 BigDecimal,所以我可能犯了一个明显的错误;但我很乐意学习,所以我向你们寻求建议:)
感谢任何帮助。
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()
0.02461134
不传递浮点类型
BigDecimal
class is to avoid the inherent inaccuracies found in floating-point技术的要点。 float
/Float
和 double
/Double
等浮点类型会牺牲准确性来换取执行速度。相比之下,BigDecimal
速度慢但准确。
您的代码:
new BigDecimal( 0.76135 )
new BigDecimal( 1.1345 )
new BigDecimal( 0.008853 )
…正在传递一个 double
原始文字。在编译过程中,您键入的文本 0.76135
被解析为数字,具体而言是 double
(64 位浮点值)。那时你已经引入了这种类型固有的不准确性。换句话说,从 0.76135
产生的 double
可能不再完全是 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 ) );
0.7613499999999999712230192017159424722194671630859375
1.13450000000000006394884621840901672840118408203125
0.0088529999999999997584154698415659368038177490234375
因此,通过创建 double
数值,您调用了浮点技术,并引入了错误。
使用字符串
解决办法?使用字符串,完全避免 double
类型。
在这些输入周围加上一些 双引号 ,然后 voilà.
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" ) );
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 );
2.78 * 0.008853 = 0.02461134
接下来你应该学习 BigDecimal
的舍入和截断。已经在 Stack Overflow 上多次提及。
问题是您假设 intCompact
表示您的浮点数的非浮点版本。在某些情况下会,但在大多数情况下不会。
例如,我试图将您的问题减少到最低限度。
import java.math.BigDecimal;
class Main {
public static void main(String[] args) {
final BigDecimal YEN_TO_USD = new BigDecimal(0.008853);
BigDecimal value = new BigDecimal(2.78);
value = value.multiply(YEN_TO_USD);
System.out.println(value);
}
}
在带有 println
的行上打断我得到以下信息:
您看到 intCompact
与您的相同 (-9223372036854775808
)。但本例中的 stringCache
是预期值。
请参阅 Basil 的回答,了解为什么您应该使用字符串而不是双精度构造 BigDecimal。
我正在 Java 制作货币转换应用程序。其他一些出色的 Whosebug 开发人员建议我阅读 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
在我用各自的 BigDecimals 替换我的双打之后 - 我决定测试它并看看它是如何工作的。
我的测试人员 class 运行使用以下方法启动转换过程。
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;
}
当我输入示例变量(将 2.78 日元转换为加元)时,我逐步完成了整个过程,发现一切正常,直到我 return 一个值。
由前面提到的方法,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);
}
所有值均已正确传递,它向下逐步找到正确的大小写 ("YEN"),并且变量窗格显示 "fromQuantity" BigDecimal 的 intCompact 值为 278(这对我来说很有意义)
一旦断点 return 回到 "convert" 方法,它就会变得一团糟。而不是 returning 2.78 * 0.008853 = 0.0246
,它 returns -9223372036854775808
.
这会导致所有其他计算产生错误。
我刚开始使用 BigDecimal,所以我可能犯了一个明显的错误;但我很乐意学习,所以我向你们寻求建议:)
感谢任何帮助。
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()
0.02461134
不传递浮点类型
BigDecimal
class is to avoid the inherent inaccuracies found in floating-point技术的要点。 float
/Float
和 double
/Double
等浮点类型会牺牲准确性来换取执行速度。相比之下,BigDecimal
速度慢但准确。
您的代码:
new BigDecimal( 0.76135 )
new BigDecimal( 1.1345 )
new BigDecimal( 0.008853 )
…正在传递一个 double
原始文字。在编译过程中,您键入的文本 0.76135
被解析为数字,具体而言是 double
(64 位浮点值)。那时你已经引入了这种类型固有的不准确性。换句话说,从 0.76135
产生的 double
可能不再完全是 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 ) );
0.7613499999999999712230192017159424722194671630859375
1.13450000000000006394884621840901672840118408203125
0.0088529999999999997584154698415659368038177490234375
因此,通过创建 double
数值,您调用了浮点技术,并引入了错误。
使用字符串
解决办法?使用字符串,完全避免 double
类型。
在这些输入周围加上一些 双引号 ,然后 voilà.
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" ) );
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 );
2.78 * 0.008853 = 0.02461134
接下来你应该学习 BigDecimal
的舍入和截断。已经在 Stack Overflow 上多次提及。
问题是您假设 intCompact
表示您的浮点数的非浮点版本。在某些情况下会,但在大多数情况下不会。
例如,我试图将您的问题减少到最低限度。
import java.math.BigDecimal;
class Main {
public static void main(String[] args) {
final BigDecimal YEN_TO_USD = new BigDecimal(0.008853);
BigDecimal value = new BigDecimal(2.78);
value = value.multiply(YEN_TO_USD);
System.out.println(value);
}
}
在带有 println
的行上打断我得到以下信息:
您看到 intCompact
与您的相同 (-9223372036854775808
)。但本例中的 stringCache
是预期值。
请参阅 Basil 的回答,了解为什么您应该使用字符串而不是双精度构造 BigDecimal。