bit manipulation - Toggle a given range of bits of an unsigned int in C -
i trying replace following piece of code
// code version 1 unsigned int time_stx = 11; // given range start unsigned int time_enx = 19; // given range end unsigned int time = 0; // desired output while(time_stx < time_enx) time |= (1 << time_stx++);
with following 1 without loop
// code version 2 unsigned int time_stx = 11; unsigned int time_enx = 19; unsigned int time = (1 << time_enx) - (1 << time_stx);
it turns out in code version 1, time = 522240;
in code version 2, time = 0;
when use
printf("%u\n", time);
to compare result. know why happening , if there faster way toggle bits in given range. compiler gcc (debian 4.9.2-10) 4.9.2.
edit:
thank replies. have made silly mistake , feel embarrassing posting question without further inspecting codes. did
unsigned int time_stx = 11; unsigned int time_enx = 19; unsigned int time1 = 0; while(time_stx < time_enx) time1 |= (1 << time_stx++); // version 1 //// should, forgotten // time_stx = 11; // time_enx = 19; // time_stx = time_enx now... unsigned int time2 = (1 << time_enx) - (1 << time_stx); // version 2 // printf("time1 = %u\n", time1); // time1 = 522240 printf("time2 = %u\n", time2); // time2 = 0
i sorry inconvenience incurred.
remark: both time_stx
, time_enx
generated in run-time , not fixed.
as suggested made mistake , problem solved now. thank you!!
read bit twiddling hacks. if answer isn't in there, you'll better educated on bit twiddling. also, original code setting bits in range; toggling means turning 1 bits 0 bits , vice versa (normally achieved using ^
or xor).
as code, converted 3 variants of expression following c code:
#include <stdio.h> static void print(unsigned int v) { printf("0x%.8x = %u\n", v, v); } static void bit_setter1(void) { unsigned int time_stx = 11; // given range start unsigned int time_enx = 19; // given range end unsigned int time = 0; // desired output while (time_stx < time_enx) time |= (1 << time_stx++); print(time); } static void bit_setter2(void) { unsigned int time_stx = 11; unsigned int time_enx = 19; unsigned int time = (1 << time_enx) - (1 << time_stx); print(time); } static void bit_setter3(void) { unsigned int time = 0xff << 11; print(time); } int main(void) { bit_setter1(); bit_setter2(); bit_setter3(); return 0; }
when @ assembler (gcc 5.1.0 on mac os x 10.10.3), get:
.globl _main _main: lfb5: lm1: lvl0: subq $8, %rsp lcfi0: lbb28: lbb29: lbb30: lbb31: lm2: movl $522240, %edx movl $522240, %esi leaq lc0(%rip), %rdi xorl %eax, %eax call _printf lvl1: lbe31: lbe30: lbe29: lbe28: lbb32: lbb33: lbb34: lbb35: movl $522240, %edx movl $522240, %esi xorl %eax, %eax leaq lc0(%rip), %rdi call _printf lvl2: lbe35: lbe34: lbe33: lbe32: lbb36: lbb37: lbb38: lbb39: movl $522240, %edx movl $522240, %esi xorl %eax, %eax leaq lc0(%rip), %rdi call _printf lvl3: lbe39: lbe38: lbe37: lbe36: lm3: xorl %eax, %eax addq $8, %rsp lcfi1: ret
that's amazingly large collection of labels!
the compiler has evaluated 3 minimal bit_settern()
functions , inlined them, along call print
, body of main()
. includes evaluating expressions 522240 each time.
compilers @ optimization. write clear code , let them @ it, , optimize better can. clearly, if 11 , 19 not fixed in code (they're sort of computed variables can vary @ runtime), precomputation isn't easy (and bit_setter3()
non-starter). non-loop code work ok, loop code.
for record, output is:
0x0007f800 = 522240 0x0007f800 = 522240 0x0007f800 = 522240
if debian compiler giving 0 1 of code fragments, there's either difference between compiled , posted, or there's bug in compiler. on whole, , no disrespect intended, more you've made mistake compiler has bug in shows in code simple this.
Comments
Post a Comment