BigDecimal 值货币
BigDecimal to values monetary
我有两个浮点值:
float value1 = 1.9f;
float value2 = 20;
我想将它们相乘并得到一个精确的结果,所以我使用 BigDecimal
并期望结果为 38:
BigDecimal total = new BigDecimal(value1).multiply(new BigDecimal(value2));
System.out.println(total); // 37.99999952316284179687500
当我用 10 和 1.9 做同样的测试时,我得到 18.99999976158142089843750 而不是 19。
为什么我会丢失精度?
假设您的 value1 是一个 double as primitive type 并且想要输出 2 个小数位并且 value1 是 350。4432567
double roundTotal = Math.round(value1 * 100.0) / 100.0;
or
double roundTotal = (double) Math.round(value1 * 100) / 100;
Output:
350.44
Note that the 2 digits precision. Zeros indicate the wanted number of decimal to display.
Example #2
double roundTotal = (double) Math.round(value1 * 10000) / 10000;
Output:
350.4432
您可以使用
Math.floor(float f);
//or
Math.ceil(float f);
精确值的函数。或者您可以为 BigDecimal class.
覆盖这些函数
这在 BigDecimal(double) 构造函数的 javadoc 中有解释:
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
虽然你的变量是浮点数,但没有接受浮点数的构造函数,所以它们被转换为双精度数。就像文档所说的那样,如果您使用字符串作为您的值,您将得到您期望的确切结果 (38)。
错误就在开头:
float value1 = 1.9f;
您可能认为 value1
现在正好包含值 1.9。但这种情况并非如此。浮点值以二进制形式存储。需要记住的重要一点是,一些实数值不能用有限的数字序列表示,例如 float
。 1.9 就是这样一个数字(就像十进制中的值 1.333... 不能用有限的数字序列表示)。
所以你应该从一开始就使用 BigDecimal
。那么这些值就可以精确表示(因为它不是以二进制存储而是以十进制存储)并且计算结果是预期的答案。
我有两个浮点值:
float value1 = 1.9f;
float value2 = 20;
我想将它们相乘并得到一个精确的结果,所以我使用 BigDecimal
并期望结果为 38:
BigDecimal total = new BigDecimal(value1).multiply(new BigDecimal(value2));
System.out.println(total); // 37.99999952316284179687500
当我用 10 和 1.9 做同样的测试时,我得到 18.99999976158142089843750 而不是 19。
为什么我会丢失精度?
假设您的 value1 是一个 double as primitive type 并且想要输出 2 个小数位并且 value1 是 350。4432567
double roundTotal = Math.round(value1 * 100.0) / 100.0;
or
double roundTotal = (double) Math.round(value1 * 100) / 100;
Output:
350.44
Note that the 2 digits precision. Zeros indicate the wanted number of decimal to display.
Example #2
double roundTotal = (double) Math.round(value1 * 10000) / 10000;
Output:
350.4432
您可以使用
Math.floor(float f);
//or
Math.ceil(float f);
精确值的函数。或者您可以为 BigDecimal class.
覆盖这些函数这在 BigDecimal(double) 构造函数的 javadoc 中有解释:
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
虽然你的变量是浮点数,但没有接受浮点数的构造函数,所以它们被转换为双精度数。就像文档所说的那样,如果您使用字符串作为您的值,您将得到您期望的确切结果 (38)。
错误就在开头:
float value1 = 1.9f;
您可能认为 value1
现在正好包含值 1.9。但这种情况并非如此。浮点值以二进制形式存储。需要记住的重要一点是,一些实数值不能用有限的数字序列表示,例如 float
。 1.9 就是这样一个数字(就像十进制中的值 1.333... 不能用有限的数字序列表示)。
所以你应该从一开始就使用 BigDecimal
。那么这些值就可以精确表示(因为它不是以二进制存储而是以十进制存储)并且计算结果是预期的答案。