mod.c
#include <stdio.h> #include <limits.h> int main(void) { int i; for (i = 0; i < INT_MAX; ++i) { if (i % 2 == 0) { printf("%d is even.\n", i); } else { printf("%d is odd.\n", i); } } return 0; }Next, I tried a bit mask. Basically, all it does is bitwise and (&) the first bit of the integer and 1:
bit.c
#include <stdio.h> #include <limits.h> int main(void) { register int i; for (i = 0; i < INT_MAX; ++i) { if (i & 1) { printf("%d is even.\n", i); } else { printf("%d is odd.\n", i); } } return 0; }Finally, I exploited the fact the integer division truncates any remainder of a number:
int.c
#include <stdio.h> #include <limits.h> int main(void) { register int i; for (i = 0; i < INT_MAX; ++i) { if ((i / 2) * 2 == i) { printf("%d is even.\n", i); } else { printf("%d is odd.\n", i); } } return 0; }I compiled each one with gcc -O2, and these were my times:
time ./mod > /dev/null ./mod > /dev/null 299.43s user 1.34s system 62% cpu 8:02.40 total time ./bit > /dev/null ./bit > /dev/null 298.97s user 1.87s system 83% cpu 5:59.71 total time ./int > /dev/null ./int > /dev/null 304.14s user 1.57s system 61% cpu 8:16.85 total
These times are not all that useful, as each program did not get the same amount of cpu. Things got a little more interesting though when I recompiled with gcc -O3, and made sure the programs could each get pretty much all of the cpu for the entirety of their run times:
time ./mod > /dev/null ./mod > /dev/null 296.04s user 1.00s system 99% cpu 4:58.53 total time ./int > /dev/null ./int > /dev/null 297.81s user 1.04s system 99% cpu 5:00.46 total time ./bit > /dev/null ./bit > /dev/null 292.43s user 1.16s system 99% cpu 4:54.79 total
Really not much difference in time at all between the three - they all took around five minutes. Without looking at the assembly for each program, these results might seem a little surprising, especially for mod.c, and bit.c. But look at the assembly for the two (and you won't be surprised about the execution time any longer):
.file "mod.c" .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "%d is even.\n" .LC1: .string "%d is odd.\n" .text .p2align 4,,15 .globl main .type main, @function main: .LFB11: .cfi_startproc pushq %rbx .cfi_def_cfa_offset 16 xorl %ebx, %ebx .cfi_offset 3, -16 jmp .L4 .p2align 4,,10 .p2align 3 .L8: movl %ebx, %esi xorl %eax, %eax movl $.LC0, %edi addl $1, %ebx call printf cmpl $2147483647, %ebx je .L7 .L4: testb $1, %bl je .L8 movl %ebx, %esi xorl %eax, %eax movl $.LC1, %edi addl $1, %ebx call printf cmpl $2147483647, %ebx jne .L4 .L7: xorl %eax, %eax popq %rbx .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE11: .size main, .-main .ident "GCC: (SUSE Linux) 4.5.0 20100604 [gcc-4_5-branch revision 160292]" .section .comment.SUSE.OPTs,"MS",@progbits,1 .string "Ospwg" .section .note.GNU-stack,"",@progbits
And bit.c:
.file "bit.c" .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "%d is even.\n" .LC1: .string "%d is odd.\n" .text .p2align 4,,15 .globl main .type main, @function main: .LFB11: .cfi_startproc pushq %rbx .cfi_def_cfa_offset 16 xorl %ebx, %ebx .cfi_offset 3, -16 jmp .L4 .p2align 4,,10 .p2align 3 .L8: movl %ebx, %esi xorl %eax, %eax movl $.LC0, %edi addl $1, %ebx call printf cmpl $2147483647, %ebx je .L7 .L4: testb $1, %bl jne .L8 movl %ebx, %esi xorl %eax, %eax movl $.LC1, %edi addl $1, %ebx call printf cmpl $2147483647, %ebx jne .L4 .L7: xorl %eax, %eax popq %rbx .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE11: .size main, .-main .ident "GCC: (SUSE Linux) 4.5.0 20100604 [gcc-4_5-branch revision 160292]" .section .comment.SUSE.OPTs,"MS",@progbits,1 .string "Ospwg" .section .note.GNU-stack,"",@progbits
They are virtually identical; the compiler turned them into almost the same program! In case you have trouble seeing where the differences lie, here is the diff for the two:
diff mod.s bit.s 1c1 < .file "mod.c" --- > .file "bit.c" 31c31 < je .L8 --- > jne .L8
You don't get much closer than that. I won't bother posting the assembly for int.c, (its just a couple more instructions) as the difference in run time is negligible. With a good optimizing compiler, what you wrote might not even end up in the final output.
No comments:
Post a Comment