以编程方式,如何编写未优化的代码来计算10个整数的总和?

时间:2016-01-12 02:32:37

标签: java android dalvik

在Java,C或C ++中,如何编写未优化的代码以编程方式计算10个整数(从0到9)的总和?

例如,我使用下面的代码,但似乎两个代码(标记为// Baseline和// Method#1的代码)在编译时由编译器优化,并且总变量转换为常量在运行之前。我通过比较相似的time1和time2确认了这一点。

我的问题是

以编程方式,如何对10个数字求和并强制编译器不优化代码(例如,没有常量传播/折叠)以避免在编译时计算总和,并且强制它仅在运行时发生< /强>

       long start, end, time1, time2, total;

    //Baseline
    start = System.nanoTime();
    total = (0+1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9);
    end = System.nanoTime();
    System.out.println("********************* The sum is " + total);
    time1 =  end - start;
    System.out.println("********************* start=" + start + " end=" + end + " time=" + time1);

    //Method #1
    start = System.nanoTime();
    total = (a0() + a1() + a2() + a3() + a4() + a5() + a6() + a7() + a8() + a9());
    end = System.nanoTime();
    System.out.println("********************* The sum is " + total);
    time2 =  end - start;
    System.out.println("********************* start=" + start + " end=" + end + " time=" + time2);

}
private int a0()
{
    return 0;
}
private int a1()
{
    return 1;
}
private int a2()
{
    return 2;
}
private int a3()
{
    return 3;
}
private int a4()
{
    return 4;
}
private int a5()
{
    return 5;
}
private int a6()
{
    return 6;
}
private int a7()
{
    return 7;
}
private int a8()
{
    return 8;
}
private int a9()
{
    return 9;
}

更新要求:

(1)仅适用于使用Dalvik编译器的Java

(2)只有原始变量,但嵌套函数(方法)是可以接受的

(3)没有波动

(4)没有循环,跳转或等待陈述

顺便说一句,我尝试了下面建议的C和C ++建议,但是它们似乎不适用于Dalvik编译器,它将加法表达式转换为常量。

4 个答案:

答案 0 :(得分:0)

只需在编译时禁用优化,就可以很容易地在C中执行此操作。参加这个C程序:

stations

使用#include <stdio.h> int main(int argc, char *argv[]) { int sum = 0; for (int i = 0; i < 10; i++) { sum += i; } printf("%d\n", sum); return 0; } 进行编译。 gcc -O0 program.c告诉GCC不要优化您的代码。如果你看看输出的程序集(可以通过添加-O0作为编译参数来完成),你可以看到它确实是前10个数字的总和:

-S

您可以看到片段末尾的跳转回到循环的开头,并在循环开始时看到条件跳转以检查... LBB0_1: ## =>This Inner Loop Header: Depth=1 cmpl $10, -24(%rbp) jge LBB0_4 ## BB#2: ## in Loop: Header=BB0_1 Depth=1 movl -24(%rbp), %eax addl -20(%rbp), %eax movl %eax, -20(%rbp) ## BB#3: ## in Loop: Header=BB0_1 Depth=1 movl -24(%rbp), %eax addl $1, %eax movl %eax, -24(%rbp) jmp LBB0_1 ... 。如果您查看优化的汇编代码(使用i < 10进行编译),您可以看到GCC展开循环并在编译时计算总和:

gcc -O3 -S program.c

我不知道你为什么要这样做。

答案 1 :(得分:0)

您可以使用数组(Java中的对象类型),然后在Java 8+中使用IntStream.sum()。像,

int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int sum = IntStream.of(arr).sum();

int sum = IntStream.range(0, 10).sum();

答案 2 :(得分:0)

godbolt是一个非常酷的在线C ++编译器,可以方便地显示汇编输出。我尝试了gcc,clang和icc,所有这些都将Angular源代码优化为编译时结果,即使在1 + 2 + 3...,但如果你编码like this

-O0

...你可以得到这样的输出(在这种情况下是GCC 5.3.0)......

// Type your code here, or load an example.
int main()
{
    register int sum = 1;
    sum += 2;
    sum += 3;
    sum += 4;
    sum += 5;
    sum += 6;
    sum += 7;
    sum += 8;
    sum += 9;
    return sum;
}

显然,每个添加都是单独完成的。这也避免了循环控制的开销,如果你引入了一个仅在运行时已知的边界的for循环,你就会有这种开销。

不过,这是什么意思?在给定相同数量的运行时已知变量的情况下,无法保证编译器将生成类似的程序集....

答案 3 :(得分:0)

你想要的是易变 ....

#include <stdio.h>

int main ( void ) {

    volatile int n = 0;

    n += 1; n += 2; n += 3; n += 4; n += 5;
    n += 6; n += 7; n += 8; n += 9; n += 10;
    printf("%d\n", n);
    return 0;
}

[编辑] 添加似乎发生在寄存器中,但每次添加有两个动作:

    movl    -4(%ebp), %eax
    addl    $2, %eax
    movl    %eax, -4(%ebp)