舍入到小数点后三位的最快方法是什么?

时间:2012-04-05 03:12:28

标签: java

SO社区是正确的,在你提出性能问题似乎比我随机猜测的方法更有意义之前分析你的代码:-)我描述了我的代码(非常密集的数学)并且没有意识到超过70%的我的代码代码显然属于我不认为是减速,四舍五入的源的部分。

static double roundTwoDecimals(double d) {
    DecimalFormat twoDForm = new DecimalFormat("#.###");
    return Double.valueOf(twoDForm.format(d));
}

我的问题是我得到的十进制数通常为.01,。02等。但有时我会得到类似.070000000001的东西(我真的只关心0.07但是浮点精度导致我的其他公式导致失败),我只想要前三位小数来避免这个问题。

那么有更好/更快的方法吗?

2 个答案:

答案 0 :(得分:15)

圆(正)数的标准方法是这样的:

double rounded = floor(1000 * doubleVal + 0.5) / 1000;

示例1:floor(1000 * .1234 + 0.5) / 1000 = floor(123.9)/1000 = 0.123
示例2:floor(1000 * .5678 + 0.5) / 1000 = floor(568.3)/1000 = 0.568

但正如@nuakh评论的那样,你总是会被某种程度上的舍入错误所困扰。如果您希望完全 3个小数位,那么最好的办法是转换为千分之一(即将所有内容乘以1000)并使用整数数据类型(intlong。)

在这种情况下,您将跳过最终除法1000并使用积分值123568进行计算。如果您希望以百分比的形式显示结果,则除以10除以显示:

123→12.3%
568→56.8%

答案 1 :(得分:3)

使用演员比使用地板或圆形更快。我怀疑HotSpot编译器会更好地优化演员表。

public class Main {
    public static final int ITERS = 1000 * 1000;

    public static void main(String... args) {
        for (int i = 0; i < 3; i++) {
            perfRoundTo3();
            perfCastRoundTo3();
        }
    }

    private static double perfRoundTo3() {
        double sum = 0.0;
        long start = 0;
        for (int i = -20000; i < ITERS; i++) {
            if (i == 0) start = System.nanoTime();
            sum += roundTo3(i * 1e-4);
        }
        long time = System.nanoTime() - start;
        System.out.printf("Took %,d ns per round%n", time / ITERS);
        return sum;
    }

    private static double perfCastRoundTo3() {
        double sum = 0.0;
        long start = 0;
        for (int i = -20000; i < ITERS; i++) {
            if (i == 0) start = System.nanoTime();
            sum += castRoundTo3(i * 1e-4);
        }
        long time = System.nanoTime() - start;
        System.out.printf("Took %,d ns per cast round%n", time / ITERS);
        return sum;
    }

    public static double roundTo3(double d) {
        return Math.round(d * 1000 + 0.5) / 1000.0;
    }

    public static double castRoundTo3(double d) {
        return (long) (d * 1000 + 0.5) / 1000.0;
    }
}

打印

Took 22 ns per round
Took 9 ns per cast round
Took 23 ns per round
Took 6 ns per cast round
Took 20 ns per round
Took 6 ns per cast round

注意:从Java 7 floor(x + 0.5)和round(x)开始,根据此问题做的事情并不完全相同。 Why does Math.round(0.49999999999999994) return 1

这将正确舍入到表示错误中。这意味着虽然结果不是精确的小数,例如0.001没有准确表示,当你使用toString()时,它将为此纠正。只有在转换为BigDecimal或执行算术运算时才会看到此表示错误。