0

Other ways to implement a circular shift?

#include <stdio.h> void char_to_bin(char c){ for(int i=0;i<8;i++){ if(c&0x80){ printf("%d",1);} else {printf("%d",0);} c=c<<1; } printf("\n"); } int main() { unsigned char a =0b11100111; char_to_bin(a); //Circular shifting for(int j=0;j<32;j++){ if(a&0x80){ a<<=1; a^=1;} else{a<<=1;} char_to_bin(a); } return 0; } https://code.sololearn.com/ch9jZG5qVA3I/?ref=app

21st May 2022, 12:10 AM
David Ortega
David Ortega - avatar
7 Réponses
+ 3
david ortega I admit my code begs explanation. First, I started with your code: if(a&0x80){ a<<=1; a^=1;} else{a<<=1;} then I reduced it to this: a = (a&0x80 != 0) | a<<1; This uses the Boolean expression to translate the high bit (0x80 or 0) down to the low bit (1 or 0). Then by using bitwise Or on left-shifted a, it mimics bit rotation. Now the final twist: On a signed char, the high bit is the sign bit. So if (a&0x80 != 0) is true, that means a is negative. So an equivalent test for the high bit is (a<0). Hence, it simplifies to: a = (a<0) |a<<1; I liked the syntax, though I had to change from unsigned to signed char. It is a faster test than above. An unsigned char does not work because it never goes negative. You could use (a>=128) instead. My first reduction above would work on both types.
24th May 2022, 4:02 AM
Brian
Brian - avatar
+ 3
Here is a version that uses the CPUs "rotate left" instruction #include <stdio.h> void char_to_bin(char c){ for(int i=0;i<8;i++){ if(c&0x80){ printf("%d",1);} else {printf("%d",0);} c=c<<1; } printf("\n"); } int main() { unsigned char a =0b11100111; char_to_bin(a); //Circular shifting for(int j=0;j<32;j++){ __asm ( "rolb $1, %0;" : "=r" (a) : "r" (a) : "cc" ); char_to_bin(a); } return 0; }
21st May 2022, 5:18 AM
Ani Jona 🕊
Ani Jona 🕊 - avatar
+ 2
I've made it into faster and smaller code, but it is doing it the same way: #include <stdio.h> void char_to_bin(char c) { for(int i=8; i; i--, c<<=1) putc('0'+(c<0), stdout); putc('\n', stdout); } int main() { char a = 0b11100111; char_to_bin(a); //Circular shifting for(int j=0; j<32; j++) { a = (a<0) | a<<1; char_to_bin(a); } return 0; }
21st May 2022, 2:20 AM
Brian
Brian - avatar
+ 2
Ani Jona 🕊 in principle, any code that comes afterward and depends on the carry flag should clear it first and not presume the carry flag is initialized to 0.
21st May 2022, 12:13 PM
Brian
Brian - avatar
+ 1
Ani Jona 🕊 You deserve an award 🏆for most authentic approach! I think the cc instruction is unnecessary. It has long been a mystery to me why Kernighan omitted a bitwise rotate operator from C!
21st May 2022, 11:18 AM
Brian
Brian - avatar
0
Thanks, Brian 😅 The documentation of ROL indicates that the flags register is affected, hence i added the cc.
21st May 2022, 11:49 AM
Ani Jona 🕊
Ani Jona 🕊 - avatar
0
From Brian: #include <stdio.h> void char_to_bin(char c) { for(int i=8; i; i--, c<<=1) putc('0'+(c<0), stdout); putc('\n', stdout); } int main() { char a = 0b11100111; char_to_bin(a); //Circular shifting for(int j=0; j<32; j++) { a = (a<0) | a<<1; char_to_bin(a); } return 0; } I don't understand how "a=(a<0)|a<<1;" works. And why if I use "unsigned char a" instead of "char a" the code doesn't work?
23rd May 2022, 11:38 PM
David Ortega
David Ortega - avatar