如何在Java中自定义舍入模式?

How to customize rounding mode in Java?

我正试图在 Java 中四舍五入。我将它发送到定义了一些舍入参数的 Fiscal 打印机。

有一个数字定义小数位数...例如x = 0.0100; 第二个数字是舍入的一些系数。例如y = 0.0050;所有大于 0.0050 的都应四舍五入为 0.01 所有小于 0.0050 的应四舍五入为 0.00。 BigDecimal 不是解决方案,因为这个数字定义了舍入模式。

在打印机的文档中,我有一些 table 带有舍入数字的示例...

我花了几个小时试图解决这个问题,但找不到解决方案。这是我当前的代码...处理数字为 x 的小数点。

Math.round(value / x) * x;

我应该如何添加数字 "y" ...我尝试了一些解决方案,但对于某些变量组合,我仍然得到错误的值。

我也检查了这个,但效果不佳...

尝试将 0.0050 添加到数字中。逻辑是,如果它小于 0.50,则将保持小于 1,当切碎时,其余部分将自动变为 0。如果更大,将高于 1,所以当切碎时,将保持 1。

这匹配除 x = 0.0100; y = 0.0100 以外的所有示例,其中 returns 15.2241 = 15.22; 15.0009 = 15.00 而不是 15.23。根据描述,应该是正确的结果。

static BigDecimal round(BigDecimal val, BigDecimal x, BigDecimal y) {
    BigDecimal remainder = val.remainder(x);
    BigDecimal base = val.subtract(remainder);
    return remainder.compareTo(y) < 0 ? base : base.add(x);
}

(编辑:已更新以处理 x = 0.0200 示例)

在没有解释为什么第三个示例不一致的情况下,这是我所能得到的最接近的结果。仅为该示例添加 special-case 代码可能无法准确反映其背后的规则,并且可能会为相似的值提供错误的结果。

另请注意,在与金钱打交道时切勿使用浮点 (float/double) 值,误差会很快累积。 BigDecimal 实例应直接从值的 String 创建,并且应使用 DecimalFormat.

将它们转换回 String

我做了这样的功能...值似乎没问题,但仍然有一个错误... x = 0.0100; y = 0.0100; 15.0009 = 15.01 应该是15.00

@SeanVanGorder 创建的代码不是很好,因为如果 x = 0.0200 ... 值是错误的。我的函数使得 x = 0.0200; y = 0.0030; 15.2241 = 15.24 应该是这样的...四舍五入到第一个 2.

Return 类型是 double,因为我没能用 BigDecimal 对变量 x 进行良好的舍入。我将只使用 return 值来写入打印机,所以浮点数等不应该有问题,但如果有人知道解决方案,请随时 post 它。这可能是我做的最好的解决方案,但它仍然不是 100% 好。

更新: 我更新了代码...现在它与 BigDecimal 完全兼容,它可能是解决这个问题的最佳方法。我给打印机制造商写了一封电子邮件,得到的回复与程序员手册中的描述相冲突。所以,这不是 100% 好的解决方案,一个值仍然是错误的 value = 15.0009; x = 0.0100; y = 0.0100; 应该是 15.00(手动),但是制造商写了 15.01 而我的代码 returns 15.01.

static BigDecimal roundVaros(BigDecimal value, BigDecimal x, BigDecimal y) {
    BigDecimal a = value.divide(x, RoundingMode.HALF_UP);
    BigDecimal b = y.divide(x, RoundingMode.HALF_UP);

    a = a.subtract(BigDecimal.valueOf(a.longValue()));
    b = b.subtract(BigDecimal.valueOf(b.longValue()));

    if (a.compareTo(b) >= 0) {
        return value.divide(x, RoundingMode.HALF_UP).setScale(0, RoundingMode.CEILING).multiply(x);
    } else {
        return value.divide(x, RoundingMode.HALF_UP).setScale(0, RoundingMode.FLOOR).multiply(x);
    }
}

感谢@SeanVanGoder(他的代码也帮助了我)