Verimli tamsayı karşılaştırma işlevi | Netgez.com
SORU
12 HAZİRAN 2012, Salı


Verimli tamsayı karşılaştırma işlevi

compare fonksiyon iki argüman a b alır ve bir tamsayı sıralarını açıklayan döndüren bir işlevdir. a b, daha küçük ise sonuç negatif tam sayı. a b, daha büyük ise sonuç pozitif bir tam sayıdır. Aksi takdirde, a b eşit ve sonuç sıfır.

Bu işlev, genellikle ve standart kütüphanelerden sıralama algoritmaları arama parametrize için kullanılır.

Karakter için compare işlevi uygulamak oldukça kolay; sadece argümanlar çıkarma:

int compare_char(char a, char b)
{
    return a - b;
}

Bu iki karakter arasındaki fark genellikle bir tamsayı içine sığacak şekilde kabul edilir, çünkü çalışır. Bu varsayım sistemleri için de geçerli değil (Not sizeof(char) == sizeof(int).)

Bu hile olamaz iki tamsayı arasındaki fark genellikle bir tamsayı içine sığmıyor çünkü tamsayılar karşılaştırın. Örnek INT_MAX -1 (teknik olarak, taşma tanımlanmamış davranışa yol açar, ama aritmetik varsayalım) daha küçük olduğunu göstermektedir.

Nasıl karşılaştırmak verimli tamsayılar için işlev hale getirebiliriz? İşte benim ilk denemem:

int compare_int(int a, int b)
{
    int temp;
    int result;
    __asm__ __volatile__ (
        "cmp %3, %2 \n\t"
        "mov $0, %1 \n\t"

        "mov $1, %0 \n\t"
        "cmovg %0, %1 \n\t"

        "mov $-1, %0 \n\t"
        "cmovl %0, %1 \n\t"
    : "=r"(temp), "=r"(result)
    : "r"(a), "r"(b)
    : "cc");
    return result;
}

6 Daha talimatları yapılabilir? Daha verimli daha kolay bir yolu var mı?

CEVAP
12 HAZİRAN 2012, Salı


Aşağıdaki her zaman benim için oldukça etkili olduğu kanıtlanmıştır:

return (a < b) ? -1 : (a > b);

gcc -O2 -S ile bu aşağı beş aşağıdaki talimatları derler:

xorl    íx, íx
cmpl    %esi, íi
movl    $-1, êx
setg    %dl
cmovge  íx, êx

Bir takip Ambroz Bizjak's excellent companion answer, onun programını yukarıda yayınlanmıştır ne aynı derleme kod test kaniyim. Ve, daha yakından derleyici çıkış okurken, derleyici bizim cevaplar da yayınlanmıştır talimatları yaratamaz olduğunu fark ettim. Bu yüzden, test programı, Kurul çıkışı modifiye el koymuştuk, ve elde edilen kez kıyasla ne maç aldım.Kabaca aynı şekilde karşılaştırmak iki sürümleri gibi görünüyor.

./opt_cmp_branchless: 0m1.070s
./opt_cmp_branch:     0m1.037s

Diğerleri aynı deney deneyin, ve ya benim gözlemi teyit aykırı olabilir ki tam olarak her programın derleme gönderiyorum.

Aşağıdaki cmovge Yönerge ((a < b) ? -1 : (a > b)) sürüm:

        .file   "cmp.c"
        .text
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "%d=0\n"
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
.LFB20:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        pushq   %rbx
        .cfi_def_cfa_offset 24
        .cfi_offset 3, -24
        movl    $arr.2789, ëx
        subq    $8, %rsp
        .cfi_def_cfa_offset 32
.L9:
        leaq    4(%rbx), %rbp
.L10:
        call    rand
        movb    %al, (%rbx)
        addq    $1, %rbx
        cmpq    %rbx, %rbp
        jne     .L10
        cmpq    $arr.2789 4096, %rbp
        jne     .L9
        xorl    %r8d, %r8d
        xorl    %esi, %esi
        orl     $-1, íi
.L12:
        xorl    ëp, ëp
        .p2align 4,,10
        .p2align 3
.L18:
        movl    arr.2789(%rbp), ìx
        xorl    êx, êx
        .p2align 4,,10
        .p2align 3
.L15:
        movl    arr.2789(%rax), íx
        xorl    ëx, ëx
        cmpl    ìx, íx
        movl    $-1, íx
        setg    %bl
        cmovge  ëx, íx
        addq    $4, %rax
        addl    íx, %esi
        cmpq    $4096, %rax
        jne     .L15
        addq    $4, %rbp
        cmpq    $4096, %rbp
        jne     .L18
        addl    $1, %r8d
        cmpl    $500, %r8d
        jne     .L12
        movl    $.LC0, íi
        xorl    êx, êx
        call    printf
        addq    $8, %rsp
        .cfi_def_cfa_offset 24
        xorl    êx, êx
        popq    %rbx
        .cfi_def_cfa_offset 16
        popq    %rbp
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
.LFE20:
        .size   main, .-main
        .local  arr.2789
        .comm   arr.2789,4096,32
        .section        .note.GNU-stack,"",@progbits

Aşağıda sürümünü şubesiz yöntemi ((a > b) - (a < b)) kullanır:

        .file   "cmp.c"
        .text
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "%d=0\n"
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
.LFB20:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        pushq   %rbx
        .cfi_def_cfa_offset 24
        .cfi_offset 3, -24
        movl    $arr.2789, ëx
        subq    $8, %rsp
        .cfi_def_cfa_offset 32
.L9:
        leaq    4(%rbx), %rbp
.L10:
        call    rand
        movb    %al, (%rbx)
        addq    $1, %rbx
        cmpq    %rbx, %rbp
        jne     .L10
        cmpq    $arr.2789 4096, %rbp
        jne     .L9
        xorl    %r8d, %r8d
        xorl    %esi, %esi
.L19:
        movl    ëp, ëx
        xorl    íi, íi
        .p2align 4,,10
        .p2align 3
.L24:
        movl    ëp, ìx
        xorl    êx, êx
        jmp     .L22
        .p2align 4,,10
        .p2align 3
.L20:
        movl    arr.2789(%rax), ìx
.L22:
        xorl    íx, íx
        cmpl    ëx, ìx
        setg    %cl
        setl    %dl
        movzbl  %cl, ìx
        subl    ìx, íx
        addl    íx, %esi
        addq    $4, %rax
        cmpq    $4096, %rax
        jne     .L20
        addq    $4, %rdi
        cmpq    $4096, %rdi
        je      .L21
        movl    arr.2789(%rdi), ëx
        jmp     .L24
.L21:
        addl    $1, %r8d
        cmpl    $500, %r8d
        jne     .L19
        movl    $.LC0, íi
        xorl    êx, êx
        call    printf
        addq    $8, %rsp
        .cfi_def_cfa_offset 24
        xorl    êx, êx
        popq    %rbx
        .cfi_def_cfa_offset 16
        popq    %rbp
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
.LFE20:
        .size   main, .-main
        .local  arr.2789
        .comm   arr.2789,4096,32
        .section        .note.GNU-stack,"",@progbits

Bunu PaylaÅŸ:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VÄ°DEO

Rastgele Yazarlar

  • adrianisen

    adrianisen

    25 Kasım 2009
  • FF Radio

    FF Radio

    16 Mayıs 2008
  • Jon Reed

    Jon Reed

    14 AÄžUSTOS 2006