执行乘法的最有效方法是什么?

时间:2015-05-31 10:00:30

标签: java performance optimization

我们说我们必须在循环中执行10000次此计算。

案例1

double answer = i * 1.6712 * 1000 * 60;

案例2

double answer = i * 100272; // 1.6712 * 1000 * 60 = 100272

其中i是循环索引。

问题

什么是最有效的方法(就CPU周期而言),案例1或2以及为什么?

1 个答案:

答案 0 :(得分:3)

以下是JMH基准:

@OutputTimeUnit(TimeUnit.SECONDS)
@BenchmarkMode({ Mode.Throughput })
@Warmup(iterations = 10)
@Fork(value = 1)
@State(Scope.Benchmark)
public class MyBenchmark {
    private static final double CONSTANT = 1.6712 * 1000 * 60;
    private double x = 0;

    @Benchmark
    public void testCaseOne() {
        for (double i = 1; i < 1000_000; i++) {
            x += i * 1.6712 * 1000 * 60;
        }
    }

    @Benchmark
    public void testCaseTwo() {
        for (double i = 1; i < 1000_000; i++) {
            x += i * (1.6712 * 1000 * 60);
        }
    }

    @Benchmark
    public void testCaseThree() {
        for (double i = 1; i < 1000_000; i++) {
            x += i * 100272;
        }
    }

    @Benchmark
    public void testCaseFour() {
        final double constant = 1.6712 * 1000 * 60;
        for (double i = 1; i < 1000_000; i++) {
            x += i * constant;
        }
    }

    @Benchmark
    public void testCaseFive() {
        for (double i = 1; i < 1000_000; i++) {
            x += i * CONSTANT;
        }
    }
}

结果:

Benchmark                   Mode  Cnt    Score    Error  Units

MyBenchmark.testCaseOne    thrpt   20  680,452 ± 15,700  ops/s
MyBenchmark.testCaseTwo    thrpt   20  721,542 ± 14,131  ops/s
MyBenchmark.testCaseThree  thrpt   20  729,411 ± 17,031  ops/s
MyBenchmark.testCaseFour   thrpt   20  735,255 ± 16,001  ops/s
MyBenchmark.testCaseFive   thrpt   20  719,481 ±  5,338  ops/s

Java版:

openjdk version "1.8.0_45-internal"
OpenJDK Runtime Environment (build 1.8.0_45-internal-b14)
OpenJDK 64-Bit Server VM (build 25.45-b02, mixed mode)

正如您所看到的,吞吐量没有显着差异,因此您可以用最清晰,更易于理解的方式编写它。

关于我之前的基准测试结果:

Benchmark                   Mode  Cnt     Score    Error  Units
MyBenchmark.testCaseOne    thrpt   20   228,285 ±  2,232  ops/s
MyBenchmark.testCaseTwo    thrpt   20   593,755 ±  8,165  ops/s
MyBenchmark.testCaseThree  thrpt   20  1035,549 ± 20,908  ops/s

以前的基准测试被打破了 - for循环中的计数器是int类型,而testCaseThree中的计数器是整数乘法,这就是它快得多的原因。其他结果也受到基准测试中此错误的影响。

虽然混合整数倍乘法比纯int-int和double-double乘法慢得多,但仍然很有趣。也许是因为类型铸造?