将Java BigDecimal舍入到最接近的间隔

问题描述 投票:15回答:3

我有一个BigDecimal计算结果,我需要四舍五入到最接近的指定间隔(在这种情况下,这是金融市场的变动幅度)。

例如价格[T号]->舍入价格

100.1 [0.25] -> 100
100.2 [0.25] -> 100.25
100.1 [0.125] -> 100.125
100.2 [0.125] -> 100.25

谢谢。

更新:schnaader的解决方案,翻译成Java / BigDecimal术语:

price = price.divide(tick).setScale(0, RoundingMode.HALF_UP).multiply(tick)
java rounding bigdecimal intervals
3个回答
14
投票

您可以标准化刻度大小,然后使用通常的舍入方法:

100.1 [0.25] -> * (1/0.25) -> 400.4 [1]  -> round -> 400 -> / (1/0.25) -> 100
100.2 [0.25] -> * (1/0.25) -> 400.8 [1] -> round -> 401 -> / (1/0.25) -> 100.25

所以应该是:

Price = Round(Price / Tick) * Tick;

还要注意,您似乎必须为BigDecimals设置正确的舍入模式。例如,请参见BigDecimal Docs。因此,您应该确保设置正确,并编写一些测试来检查代码的正确性。


1
投票
p= p - p % t + ((p % t < t / 2) ? 0.0 : t);

//其中,p =价格,t =报价增量


1
投票

这与“将股票价格调整为最接近的刻度大小]

schnaader提供的答案是正确的,但是缺少一些内容。

  • 首先,您必须检查股价是否需要四舍五入。不必要的舍入会弄乱小数部分。
  • 然后,您还需要处理在ArithmeticException除法功能中可能出现的BigDecimal

这是我的解决方案。解释它会花费很多时间。我建议您尝试一些示例以尝试一下。查找功能roundTick()

import static java.math.RoundingMode.HALF_UP;

import java.math.BigDecimal;

/**
 * Utility class for stock price related operations.
 */
public final class PriceFormatter {

    public static final float DELTA = 0.0001f;

    private PriceFormatter() {
    }

    /**
     * Rounds the price to the nearest tick size.
     *
     * @param price    price
     * @param tickSize tick size
     * @return price rounded to the nearest tick size
     */
    public static final float roundTick(final float price, final float tickSize) {
        if (tickSize < DELTA) {
            return price;
        }

        if (!isRoundingNeeded(price, tickSize)) {
            return price;
        }

        final BigDecimal p = new BigDecimal(price);
        final BigDecimal t = new BigDecimal(tickSize);

        final BigDecimal roundedPrice = p.divide(t, 0, HALF_UP).multiply(t);

        return roundedPrice.floatValue();
    }

    /**
     * Checks whether price needs rounding to the nearest tick size.
     *
     * @param price    price
     * @param tickSize tick size
     * @return true, if rounding is needed; false otherwise
     */
    public static final boolean isRoundingNeeded(final float price, final float tickSize) {
        final int mult = calculateTickMultiplier(tickSize);
        final int mod = (int) (tickSize * mult);
        final float reminder = (((price * mult) % mult) % mod);
        final boolean needsRounding = reminder > DELTA;
        return needsRounding;
    }

    public static final int calculateTickMultiplier(final float tickSize) {
        int result = 1;
        while (((tickSize * result) < 1) || (((tickSize * result) - (int) (tickSize * result)) > DELTA)) {
            result *= 10;
        }

        return result;
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.