Java 8 BigDecimal multiply 方法在倒数时丢失精度
Java 8 BigDecimal multiply method losing precision when being inverted
Java 8 在这里。根据 Google:
- 将磅换算成千克:multiply by 0.453592
- 将千克换算成磅:multiply by 2.20462
- 将英寸换算为米:multiply by 0.0254
- 将米换算成英寸:multiply by 39.3701
所以我编写了这个 Java 代码:
public class MeasurementConverter {
private static final int SCALE = 2;
public static void main(String[] args) {
new MeasurementConverter().run();
}
private void run() {
BigDecimal hundredLbs = new BigDecimal(100.00);
BigDecimal hundredInches = new BigDecimal(100.00);
System.out.println(hundredLbs + " pounds is " + poundsToKilos(hundredLbs) + " kilos and converts back to " + kilosToPounds(poundsToKilos(hundredLbs)) + " pounds.");
System.out.println(hundredInches + " inches is " + inchesToMeters(hundredInches) + " meters and converts back to " + metersToInches(inchesToMeters(hundredInches)) + " inches.");
}
private BigDecimal metersToInches(BigDecimal meters) {
return meters.multiply(new BigDecimal("39.3701").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
}
private BigDecimal inchesToMeters(BigDecimal inches) {
return inches.multiply(new BigDecimal("0.0254").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
}
private BigDecimal kilosToPounds(BigDecimal kilos) {
return kilos.multiply(new BigDecimal("2.20462").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
}
private BigDecimal poundsToKilos(BigDecimal pounds) {
return pounds.multiply(new BigDecimal("0.45359").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
}
}
运行时打印出:
100 pounds is 45.00 kilos and converts back to 99.0000 pounds.
100 inches is 3.00 meters and converts back to 118.1100 inches.
虽然我期待它打印出来:
100.00 pounds is 45.00 kilos and converts back to 100.00 pounds.
100.00 inches is 3.00 meters and converts back to 100.00 inches.
我只关心英制<->公制转换精确到小数点后两位,最终输出始终精确到小数点后两位。 谁能看出我哪里出错了,解决方法是什么?
乘法的 SCALE 和 HALF_UP 参数不是吗?您只将它添加到 BigDecimal。
我想你想要:
inches.multiply(new BigDecimal("0.0254"), new MathContext(SCALE, RoundingMode.HALF_UP));
将 SCALE 更改为 8 并将您的代码与 MathContext 一起使用导致:
100 pounds is 45.35900 kilos and converts back to 99.999359 pounds.
100 inches is 2.5400 meters and converts back to 100.00005 inches.
您的转换系数已关闭。您将转换系数四舍五入到小数点后两位:
private static final int SCALE = 2;
[...]
new BigDecimal("0.0254").setScale(SCALE, BigDecimal.ROUND_HALF_UP)
因此,"0,0254" 向上舍入为 0.03,这不适合您的 "reverse" 转换39.37 的因数。这就是为什么您的逆转不等于原始值的原因。
你把括号弄乱了。考虑一下:
kilos.multiply(new BigDecimal("2.20462").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
在这里,您首先在 2.20462
上设置比例,结果是 2.20
,然后相乘。
现在考虑反向转换:
pounds.multiply(new BigDecimal("0.45359").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
在这里你有效地乘以 0.45
。 2.2*0.45=0.99
解释了结果。
您设置了乘法结果的比例,而不是乘法器。基本上最后一个括号在错误的地方。它应该是这样的:
pounds.multiply(new BigDecimal("0.45359")).setScale(SCALE, BigDecimal.ROUND_HALF_UP);
这是 corrected code。
您正在转换过程中进行舍入。因此,反向操作的输入值已经关闭。
如果要将值显示为:
100.00 pounds is 45.00 kilos and converts back to 100.00 pounds.
100.00 inches is 3.00 meters and converts back to 100.00 inches.
从所有私有方法中删除 setScale
。例如:
private BigDecimal metersToInches(BigDecimal meters) {
return meters.multiply(new BigDecimal("39.3701"));
}
然后您可以简单地将输出格式化为您想要的格式:
private BigDecimal formatOutput(BigDecimal value) {
return value.setScale(0, BigDecimal.ROUND_HALF_UP).setScale(SCALE);
}
最后:
System.out.println(hundredLbs + " pounds is " + formatOutput(poundsToKilos(hundredLbs)) + " kilos and converts back to " + formatOutput(kilosToPounds(poundsToKilos(hundredLbs))) + " pounds.");
System.out.println(hundredInches + " inches is " + formatOutput(inchesToMeters(hundredInches)) + " meters and converts back to " + formatOutput(metersToInches(inchesToMeters(hundredInches))) + " inches.");
给出:
100.00 pounds is 45.00 kilos and converts back to 100.00 pounds.
100.00 inches is 3.00 meters and converts back to 100.00 inches.
或者,如果您想显示带小数位的值,您只需将 formatOutput
方法更改为:
private BigDecimal formatOutput(BigDecimal value) {
return value.setScale(SCALE, BigDecimal.ROUND_HALF_UP);
}
这将按以下方式打印出值(我认为它更好更正确!)
100.00 pounds is 45.36 kilos and converts back to 100.00 pounds.
100.00 inches is 2.54 meters and converts back to 100.00 inches.
Java 8 在这里。根据 Google:
- 将磅换算成千克:multiply by 0.453592
- 将千克换算成磅:multiply by 2.20462
- 将英寸换算为米:multiply by 0.0254
- 将米换算成英寸:multiply by 39.3701
所以我编写了这个 Java 代码:
public class MeasurementConverter {
private static final int SCALE = 2;
public static void main(String[] args) {
new MeasurementConverter().run();
}
private void run() {
BigDecimal hundredLbs = new BigDecimal(100.00);
BigDecimal hundredInches = new BigDecimal(100.00);
System.out.println(hundredLbs + " pounds is " + poundsToKilos(hundredLbs) + " kilos and converts back to " + kilosToPounds(poundsToKilos(hundredLbs)) + " pounds.");
System.out.println(hundredInches + " inches is " + inchesToMeters(hundredInches) + " meters and converts back to " + metersToInches(inchesToMeters(hundredInches)) + " inches.");
}
private BigDecimal metersToInches(BigDecimal meters) {
return meters.multiply(new BigDecimal("39.3701").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
}
private BigDecimal inchesToMeters(BigDecimal inches) {
return inches.multiply(new BigDecimal("0.0254").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
}
private BigDecimal kilosToPounds(BigDecimal kilos) {
return kilos.multiply(new BigDecimal("2.20462").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
}
private BigDecimal poundsToKilos(BigDecimal pounds) {
return pounds.multiply(new BigDecimal("0.45359").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
}
}
运行时打印出:
100 pounds is 45.00 kilos and converts back to 99.0000 pounds.
100 inches is 3.00 meters and converts back to 118.1100 inches.
虽然我期待它打印出来:
100.00 pounds is 45.00 kilos and converts back to 100.00 pounds.
100.00 inches is 3.00 meters and converts back to 100.00 inches.
我只关心英制<->公制转换精确到小数点后两位,最终输出始终精确到小数点后两位。 谁能看出我哪里出错了,解决方法是什么?
乘法的 SCALE 和 HALF_UP 参数不是吗?您只将它添加到 BigDecimal。
我想你想要:
inches.multiply(new BigDecimal("0.0254"), new MathContext(SCALE, RoundingMode.HALF_UP));
将 SCALE 更改为 8 并将您的代码与 MathContext 一起使用导致:
100 pounds is 45.35900 kilos and converts back to 99.999359 pounds.
100 inches is 2.5400 meters and converts back to 100.00005 inches.
您的转换系数已关闭。您将转换系数四舍五入到小数点后两位:
private static final int SCALE = 2;
[...]
new BigDecimal("0.0254").setScale(SCALE, BigDecimal.ROUND_HALF_UP)
因此,"0,0254" 向上舍入为 0.03,这不适合您的 "reverse" 转换39.37 的因数。这就是为什么您的逆转不等于原始值的原因。
你把括号弄乱了。考虑一下:
kilos.multiply(new BigDecimal("2.20462").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
在这里,您首先在 2.20462
上设置比例,结果是 2.20
,然后相乘。
现在考虑反向转换:
pounds.multiply(new BigDecimal("0.45359").setScale(SCALE, BigDecimal.ROUND_HALF_UP));
在这里你有效地乘以 0.45
。 2.2*0.45=0.99
解释了结果。
您设置了乘法结果的比例,而不是乘法器。基本上最后一个括号在错误的地方。它应该是这样的:
pounds.multiply(new BigDecimal("0.45359")).setScale(SCALE, BigDecimal.ROUND_HALF_UP);
这是 corrected code。
您正在转换过程中进行舍入。因此,反向操作的输入值已经关闭。
如果要将值显示为:
100.00 pounds is 45.00 kilos and converts back to 100.00 pounds.
100.00 inches is 3.00 meters and converts back to 100.00 inches.
从所有私有方法中删除 setScale
。例如:
private BigDecimal metersToInches(BigDecimal meters) {
return meters.multiply(new BigDecimal("39.3701"));
}
然后您可以简单地将输出格式化为您想要的格式:
private BigDecimal formatOutput(BigDecimal value) {
return value.setScale(0, BigDecimal.ROUND_HALF_UP).setScale(SCALE);
}
最后:
System.out.println(hundredLbs + " pounds is " + formatOutput(poundsToKilos(hundredLbs)) + " kilos and converts back to " + formatOutput(kilosToPounds(poundsToKilos(hundredLbs))) + " pounds.");
System.out.println(hundredInches + " inches is " + formatOutput(inchesToMeters(hundredInches)) + " meters and converts back to " + formatOutput(metersToInches(inchesToMeters(hundredInches))) + " inches.");
给出:
100.00 pounds is 45.00 kilos and converts back to 100.00 pounds.
100.00 inches is 3.00 meters and converts back to 100.00 inches.
或者,如果您想显示带小数位的值,您只需将 formatOutput
方法更改为:
private BigDecimal formatOutput(BigDecimal value) {
return value.setScale(SCALE, BigDecimal.ROUND_HALF_UP);
}
这将按以下方式打印出值(我认为它更好更正确!)
100.00 pounds is 45.36 kilos and converts back to 100.00 pounds.
100.00 inches is 2.54 meters and converts back to 100.00 inches.