代码之家  ›  专栏  ›  技术社区  ›  smeeb

Java 8 BigDecimal乘法在反转时丢失精度

  •  4
  • smeeb  · 技术社区  · 6 年前

    这里是Java 8。据谷歌称:

    所以我编写了以下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.
    

    我所关心的就是那个帝国主义者<-&燃气轮机;公制转换精确到小数点后2位,最终输出始终精确到小数点后2位。 有人知道我哪里出错了吗?解决方法是什么?

    4 回复  |  直到 6 年前
        1
  •  3
  •   lexicore    6 年前

    你把支架弄乱了。考虑一下这一点:

    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 .

        2
  •  3
  •   Marcos Vasconcelos    6 年前

    乘法的SCALE和HALF\u UP参数不是吗?您只将其添加到BigDecimal。

    我想你想要:

    inches.multiply(new BigDecimal("0.0254"), new MathContext(SCALE, RoundingMode.HALF_UP));
    

    将比例更改为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.
    
        3
  •  0
  •   Lykanion    6 年前

    您的换算系数已关闭。您将转换系数四舍五入到小数点后两位:

    private static final int SCALE = 2;
    [...]    
    new BigDecimal("0.0254").setScale(SCALE, BigDecimal.ROUND_HALF_UP)
    

    因此 "0,0254" 四舍五入到 0.03 ,这不符合您的“反向”转换系数 39.37 . 这就是为什么你的反转不等于原值。

        4
  •  0
  •   iaforek    6 年前

    您正在转换过程中进行舍入。因此,反向操作的输入值已关闭。

    如果要将值显示为:

    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磅等于45.00公斤,换算回100.00磅。
    100.00英寸为3.00米,转换回100.00英寸。
    

    或者,如果要显示带小数点的值,只需更改 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.