902 votes

Le code C++ pour tester la conjecture de Collatz est plus rapide que l'assembleur écrit à la main - pourquoi ?

J'ai écrit ces deux solutions pour Projet Euler Q14 en assembleur et en C++. Il s'agit de la même approche de force brute identique pour tester les conjecture de Collatz . La solution de montage a été assemblée avec

nasm -felf64 p14.asm && gcc p14.o -o p14

Le C++ a été compilé avec

g++ p14.cpp -o p14

Montage, p14.asm

section .data
    fmt db "%d", 10, 0

global main
extern printf

section .text

main:
    mov rcx, 1000000
    xor rdi, rdi        ; max i
    xor rsi, rsi        ; i

l1:
    dec rcx
    xor r10, r10        ; count
    mov rax, rcx

l2:
    test rax, 1
    jpe even

    mov rbx, 3
    mul rbx
    inc rax
    jmp c1

even:
    mov rbx, 2
    xor rdx, rdx
    div rbx

c1:
    inc r10
    cmp rax, 1
    jne l2

    cmp rdi, r10
    cmovl rdi, r10
    cmovl rsi, rcx

    cmp rcx, 2
    jne l1

    mov rdi, fmt
    xor rax, rax
    call printf
    ret

C++, p14.cpp

#include <iostream>

using namespace std;

int sequence(long n) {
    int count = 1;
    while (n != 1) {
        if (n % 2 == 0)
            n /= 2;
        else
            n = n*3 + 1;

        ++count;
    }

    return count;
}

int main() {
    int max = 0, maxi;
    for (int i = 999999; i > 0; --i) {
        int s = sequence(i);
        if (s > max) {
            max = s;
            maxi = i;
        }
    }

    cout << maxi << endl;
}

Je connais les optimisations du compilateur pour améliorer la vitesse et tout le reste, mais je ne vois pas beaucoup de moyens d'optimiser davantage ma solution en assembleur (en parlant de manière programmatique et non mathématique).

Le code C++ a un modulus à chaque terme et une division à chaque terme pair, alors que l'assemblage n'a qu'une division par terme pair.

Mais l'assemblage prend en moyenne 1 seconde de plus que la solution C++. Comment cela se fait-il ? Je vous le demande principalement par curiosité.

Temps d'exécution

Mon système : Linux 64 bits sur Intel Celeron 2955U 1.4 GHz (microarchitecture Haswell).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X