关于java:舍入到三位小数的最快方法是什么?

What is the fastest way to round to three decimal places?

So社区是对的,在你问性能问题之前分析你的代码似乎比我随机猜测的方法更有意义:—)我分析了我的代码(非常密集的数学),没有意识到超过70%的代码显然在某种程度上,我不认为是减速的原因,小数四舍五入。

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

我的问题是我得到的十进制数通常是0.01,.02等,但有时我得到的是0.07000000001(我真的只关心0.07,但浮点精度会导致我的其他公式失败),我只是希望前3位小数避免这个问题。

那么,有没有更好/更快的方法来做到这一点?


将(正数)取整的标准方法如下:

1
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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;
    }
}

印刷品

1
2
3
4
5
6
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层(x+1)和圆(x),不做与这个问题完全相同的事情。为什么Math.Round(0.49999999999994)返回1

这将正确地四舍五入到表示错误内。这意味着,虽然结果不精确,但十进制(例如0.001)并没有精确表示,但当您使用toString()时,它将对此进行更正。只有当您转换为bigdecimal或执行算术运算时,才会看到此表示错误。