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
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
Tamsayı tabanlı bir güç işlevi uygulam...
Verimli paralel olarak gruplandırılmış...
Bir tamsayı verimli şekilde basamak sa...
() Java Tamsayı compareTo - neden çıka...
C 11 std::lambda karşılaştırma işlevi ...