├── .editorconfig ├── 1.0_introduction.c ├── 1.1_printing_bits.c ├── 1.2_reverse_bits.c ├── 1.3_is_power_of_2.c ├── 1.4_parsing.c ├── 1.5_clear_all_bits.c ├── 1.6_binary_gap.c ├── 1.7_align_size.c ├── 1.8_reverse_bits_template.cpp ├── 1.9_reverse_bits_assembly.cpp ├── 2.0_bsr.cpp ├── README.md └── bitwise.h /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_size = 4 3 | indent_style = tab 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /1.0_introduction.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ** 1.0 : Introduction to bitwise operators 3 | **********************************************************************/ 4 | 5 | /* 6 | ** NB : an integer contains 4 bytes, as one byte = 8 bits it means that 7 | ** an integer is equivalent to 32 bits. 8 | ** octet and byte means the same thing. 9 | ** an unsigned char has only 1 byte (8 bits). 10 | ** Now what is a bit ? It is simple, a bit is either true or false, 11 | ** equal to 1 or to 0. Binary is same as our decimal system except base 12 | ** is 2 instead of 10: 1 will be 1 but 10 will be 2 and 11 will be 3. 13 | ** to illustrate better this system take a glance at the table below : 14 | ** 15 | ** base 10 <=> base 2 16 | ** 1 <=> 1 4 <=> 100 17 | ** 2 <=> 10 5 <=> 101 and so on... 18 | ** 3 <=> 11 6 <=> 110 19 | ** 20 | ** Read more : https://en.wikipedia.org/wiki/Bit 21 | */ 22 | 23 | #include "bitwise.h" 24 | 25 | /* 26 | ** Now our program to understand bitwise operators (following explanations) 27 | ** 28 | ** 1) We set our integer to 3 (00000000 00000000 00000000 00000011) 29 | ** and our unsigned char to 46 (00101110); 30 | ** 31 | ** 2) LEFT SHIFT (<<) : byte = byte << 1; equivalent to byte * 2. 32 | ** 11 will slide to the left to become 110 33 | ** in the example 11 (3) becomes 110 (6) 34 | ** 35 | ** 3) RIGHT SHIFT (>>) : byte is now divided by 2, with the modulo being 36 | ** lost forever if we had 7 it will become 3. 37 | ** 38 | ** 4) Bitwise AND operator (&) : we now use a mask (&), with 1, 39 | ** &= 1 is equivalent to %= 2; Hence we will check if the value is odd. 40 | ** 41 | ** 5) Bitwise OR operator (|) : 42 | ** we add 1 to the number if it was even (multiple of 2). 43 | ** if it was already odd nothing will change. 44 | ** 45 | ** 6) Bitwise AND operator (&) with clearing (~) : 46 | ** Now we substract 1 to the number if it was odd. 47 | ** if it was already even nothing will change. 48 | ** 49 | ** 7) Bitwise EXCLUSIVE OR operator (^) : compares each bit of its first 50 | ** operand to the corresponding bit of its second operand. 51 | ** If one bit is 0 and the other bit is 1, the corresponding result bit 52 | ** is set to 1. Otherwise, the corresponding result bit is set to 0. 53 | ** in short: it will become 1 if bits are opposite and 0 if not. 54 | ** 00101110 = 00101110 ^ 11010000 will give 11111110 55 | */ 56 | 57 | int main(int ac, char **av) 58 | { 59 | int thirty_two_bits; 60 | unsigned char one_byte; 61 | 62 | thirty_two_bits = 3; // 1) 63 | one_byte = 46; 64 | 65 | printf("binary value : %bd\n", thirty_two_bits); 66 | thirty_two_bits <<= 1; // 2) 67 | printf("new binary value : %bd\n", thirty_two_bits); 68 | thirty_two_bits >>= 1; // 3) 69 | printf("new binary value : %bd\n", thirty_two_bits); 70 | thirty_two_bits &= 1; // 4) 71 | printf("new binary value : %bd\n", thirty_two_bits); 72 | 73 | one_byte = 46; // reminder 74 | printf("binary value : %bd\n", one_byte); 75 | one_byte |= 1; // 5) 76 | printf("new binary value : %bd\n", one_byte); 77 | one_byte &= ~1; // 6) 78 | printf("back to original value : %bd\n", one_byte); 79 | one_byte ^= 0b11010000; // 7) 00101110 = 00101110 ^ 11010000 80 | printf("new binary value : %bd\n", one_byte); 81 | return (0); 82 | } 83 | -------------------------------------------------------------------------------- /1.1_printing_bits.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ** 1.1 : Print bits 3 | **********************************************************************/ 4 | 5 | /* 6 | ** This a vanilla question for interviews : 7 | ** Write a function that takes a byte, and prints it in binary 8 | ** Your function must be declared as follows: 9 | ** void print_bits(unsigned char octet); 10 | ** Example, if you pass 2 to print_bits, it will print "00000010" 11 | */ 12 | 13 | #include "bitwise.h" 14 | 15 | /* 16 | ** First Method is standard while the second one use bitwise operators 17 | */ 18 | 19 | void print_bits(unsigned char octet) 20 | { 21 | int i; 22 | 23 | i = 128; 24 | while (octet >= 0 && i) 25 | { 26 | (octet / i) ? write(1, "1", 1) : write(1, "0", 1); 27 | (octet / i) ? octet -= i : 0; 28 | i /= 2; 29 | } 30 | } 31 | 32 | void print_bits2(unsigned char octet) 33 | { 34 | int i = 256; 35 | while (i >>= 1) 36 | (octet & i) ? write(1, "1", 1) : write(1, "0", 1); 37 | } 38 | 39 | int main(void) 40 | { 41 | int n = 64; 42 | print_bits(n); 43 | write(1, "\n", 1); 44 | print_bits2(n); 45 | write(1, "\n", 1); 46 | } -------------------------------------------------------------------------------- /1.2_reverse_bits.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ** 1.2 : Reversing bits on an octet (octet means 8 bits or 1 byte) 3 | **********************************************************************/ 4 | 5 | /* 6 | ** This a vanilla question for interviews : 7 | ** Write a function that takes a byte, reverses it, bit by bit (like the 8 | ** example) and returns the result. 9 | ** 10 | ** Your function must be declared as follows: 11 | ** 12 | ** unsigned char reverse_bits(unsigned char octet); 13 | ** 14 | ** Example: 15 | ** 16 | ** 1 byte 17 | ** _____________ 18 | ** 0100 0001 19 | ** || 20 | ** \/ 21 | ** 1000 0010 22 | */ 23 | 24 | #include "bitwise.h" 25 | 26 | /********************************************************************** 27 | ** 1st Method, for mortals like us ;) 28 | *********************************************************************** 29 | ** 1) As a byte is equal to 8 it means we will do it while (byte_len--) 30 | ** 31 | ** 2) We first check if b as a bit on the extreme right with (b & 1); 32 | ** if so we light bit 1 on r and move it juste 1 bit on the left by 33 | ** multiplying r by 2 with (r << 1) 34 | ** 35 | ** For novices: r = (r << 1) | (b & 1) might be easier to understand as: 36 | ** 37 | ** if (b % 2) | (b & 1) 38 | ** r = r + 1 39 | ** r *= 2; (r << 1) 40 | ** 41 | ** 3) Then we divide our unsigned char b by 2 to erase 42 | ** the bit located on the extreme right of the variable b. 43 | ** For reminder b >>= 1; is equivalent to b /= 2; 44 | */ 45 | 46 | unsigned char reverse_bits(unsigned char b) 47 | { 48 | unsigned char r = 0; 49 | unsigned byte_len = 8; 50 | 51 | while (byte_len--) 52 | { 53 | r = (r << 1) | (b & 1); 54 | b >>= 1; 55 | } 56 | return (r); 57 | } 58 | 59 | /********************************************************************** 60 | ** 2nd Method, swap bits 4 by 4, 2 by 2 and then 1 by 1 61 | *********************************************************************** 62 | ** 63 | ** 1) The first formula swaps 4 by 4 by applying masks: 64 | ** (b & 0xF0) >> 4 applies a mask to the higher 4 bits 65 | ** (0x0F = 1111 0000) then move them to the right. 66 | ** (b & 0x0F) << 4 applies a mask to the lowest 4 bits 67 | ** (0x0F = 0000 1111) then move them to the left. 68 | ** 69 | ** 2) Now swapthem 2 by 2: 0xCC = 1100 1100 and 0x33 = 0011 0011 70 | ** 71 | ** 3) Finally swap 1 by 1: 0xAA = 1010 1010 and 0x55 = 0101 0101 72 | ** 73 | ** if you had byte b equal to 0111 0100 ('t') it will gradually becomes: 74 | ** 1) 0100 0111 ('G') 75 | ** 2) 00 01 11 01 (character 29, group separator, not a printable char) 76 | ** 3) 0 0 1 0 1 1 1 0 = 0010 1110 ('.') 77 | */ 78 | 79 | unsigned char reverse_bits2(unsigned char b) 80 | { 81 | b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; // 1) 82 | b = (b & 0xCC) >> 2 | (b & 0x33) << 2; // 2) 83 | b = (b & 0xAA) >> 1 | (b & 0x55) << 1; // 3) 84 | return (b); 85 | } 86 | 87 | /********************************************************************** 88 | ** 3rd Method, attributed to Rich Schroeppel in the Programming Hacks 89 | ** section http://www.inwap.com/pdp10/hbaker/hakmem/hakmem.html 90 | *********************************************************************** 91 | ** 92 | ** 1) The multiply operation (b * 0x0202020202ULL) creates five separate 93 | ** copies of the 8-bit byte pattern to fan-out into a 64-bit value. 94 | ** 95 | ** 2) The AND operation (& 0x010884422010ULL) selects the bits that are in the 96 | ** correct (reversed) positions, relative to each 10-bit groups of bits. 97 | ** 98 | ** 3) Together the multiply and the AND operations copy the bits from the original 99 | ** byte so they each appear in only one of the 10-bit sets. 100 | ** The reversed positions of the bits from the original byte coincide with their 101 | ** relative positions within any 10-bit set. 102 | ** 103 | ** 4) The last step (% 0x3ff), which involves modulus division by 2^10 - 1 104 | ** has the effect of merging together each set of 10 bits 105 | ** (from positions 0-9, 10-19, 20-29, ...) in the 64-bit value. 106 | ** They do not overlap, so the addition steps underlying the modulus 107 | ** division behave like OR operations. 108 | */ 109 | 110 | unsigned char reverse_bits3(unsigned char b) 111 | { 112 | b = (b * 0x0202020202ULL & 0x010884422010ULL) % 0x3ff; 113 | return (b); 114 | } 115 | 116 | /* 117 | ** Test program : . (equal to 046 in ASCII table, 00101110 in binary) 118 | ** becomes t (116 in ASCII table, 01110100 in binary). 119 | ** byte 00101110 ('.') is indeed the reverse of byte 01110100 ('t'). 120 | */ 121 | 122 | int main(void) 123 | { 124 | unsigned char c; 125 | 126 | c = '.'; 127 | write(1, &c, 1); 128 | write(1, "\n", 1); 129 | c = reverse_bits(c); 130 | write(1, &c, 1); 131 | write(1, "\n", 1); 132 | c = reverse_bits2(c); 133 | write(1, &c, 1); 134 | write(1, "\n", 1); 135 | c = reverse_bits3(c); 136 | write(1, &c, 1); 137 | write(1, "\n", 1); 138 | return (0); 139 | } 140 | -------------------------------------------------------------------------------- /1.3_is_power_of_2.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ** 1.3 : Checking if an unsigned integer is power of 2 3 | **********************************************************************/ 4 | 5 | /* 6 | ** This a vanilla question for interviews : 7 | ** Write a function that determines if a given number is a power of 2. 8 | ** This function returns 1 if the given number is a power of 2, otherwise it returns 0. 9 | ** Your function must be declared as follows: 10 | ** int is_power_of_2(unsigned int n); 11 | */ 12 | 13 | #include "bitwise.h" 14 | 15 | /* 16 | ** first the basic function 17 | */ 18 | 19 | int is_power_of_2(unsigned int n) 20 | { 21 | if (n == 0) 22 | return (0); 23 | while (n % 2 == 0) // or alternatively (!(n % 2)) 24 | n /= 2; 25 | return ((n == 1) ? 1 : 0); // equivalent to : if (n == 1) return 1; else return (0); 26 | } 27 | 28 | /* 29 | ** Now the bitwise version : 30 | ** we apply n - 1 mask to n, and then check that is equal to 0 31 | ** it will be true for all numbers that are power of 2. 32 | ** Lastly we make sure that n is superior to 0. 33 | */ 34 | 35 | int is_power_of_2(unsigned int n) 36 | { 37 | return (n > 0 && !(n & (n - 1))); 38 | } 39 | 40 | /* 41 | ** Test program 42 | */ 43 | 44 | int main(int ac, char **av) 45 | { 46 | if (ac == 2) 47 | { 48 | printf("%s is power of 2 ?"); 49 | is_power_of_2(atoi(av[1])) ? printf("Yes\n") : printf("No\n"); 50 | } 51 | return (0); 52 | } 53 | -------------------------------------------------------------------------------- /1.4_parsing.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ** 1.4 : Parsing flag using bitwise operations whatever the project is 3 | **********************************************************************/ 4 | 5 | #include "bitwise.h" 6 | 7 | /* 8 | ** First we build the ft_strchr_index function which is similar to libft strchr 9 | ** but instead returns the character index in a string 10 | */ 11 | 12 | static int ft_strchr_index(char *s, int c) 13 | { 14 | int i; 15 | 16 | i = 0; 17 | while (s[i]) 18 | { 19 | if (s[i] == c) 20 | return (i); 21 | ++i; 22 | } 23 | return (-1); 24 | } 25 | 26 | /* 27 | ** Then we create the function parse_options which receive av[1] 28 | ** and our variable pointer address. 29 | ** 30 | ** a) Here we light the nth bit according to the parsed flag 31 | ** Firstly define flags as power of 2 in the header.h : 32 | ** # define FLAG_A 1 # define FLAG_B 2 33 | ** # define FLAG_C 4 # define FLAG_D 8 34 | ** etc. if more flags necessary. 35 | ** 36 | ** b) Then we send input from user after we find a '-' character 37 | ** hence the while (*(++s)) in order to skip it. 38 | ** if the string does not contain abcd it will return the USAGE 39 | ** 40 | ** c) Each time the function str_chr_index, we will light the bit corresponding. 41 | ** for example if we use /a.out -c we will get n equal to 2 (a starting at 0). 42 | */ 43 | 44 | int parse_options(char *s, int *flags) 45 | { 46 | int n; 47 | 48 | while (*(++s)) // b) 49 | { 50 | if ((n = ft_strchr_index("abcd", *s)) == -1) 51 | error(s, USAGE); // b) 52 | *flags |= (1 << n); // c) 53 | } 54 | return (1); 55 | } 56 | 57 | /* 58 | ** Lastly a small example on how to use it. 59 | ** 60 | ** a) We check that exactly one parameter was sent starting with '-'. 61 | ** 62 | ** b) Remember that FLAG_C is defined as 4 in the header.h file 63 | ** if (flag & 4) also means (flag % 5) 64 | ** 65 | ** c) If flag A was ON it will toggle flag B OFF by clearing bit FLAG_B (2). 66 | */ 67 | 68 | int main(int ac, char **av) 69 | { 70 | int flags; 71 | 72 | if (ac == 2 && *av[1] == '-') 73 | parse_options(av[1], &flags); // a) 74 | printf("value : %d\n", flags); // our variable raw value 75 | printf("binary value : %bd\n", flags); // displayed as a binary number 76 | if (flags & FLAG_C) // b) , 77 | printf("c flag ON"); 78 | if (flags & FLAG_B && flags & FLAG_D) // replace 2 by FLAG_B and 8 by FLAG_D 79 | printf("Both flags b and d are together ON"); 80 | if (flags & FLAG_A && flag & FLAG_B) // replace 1 by FLAG_A and 2 by FLAG_B 81 | { 82 | *flags &= ~FLAG_B; // c) 83 | printf("As flag A was ON, flag B is switched OFF"); 84 | printf("new binary value : %bd\n", flags); 85 | } 86 | return (0); 87 | } 88 | -------------------------------------------------------------------------------- /1.5_clear_all_bits.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void ft_putchar(char c) 4 | { 5 | write(1, &c, 1); 6 | } 7 | 8 | void ft_putnbr(int nb) 9 | { 10 | if (nb == -2147483648) 11 | { 12 | ft_putchar('-'); 13 | ft_putchar('2'); 14 | nb = 147483648; 15 | } 16 | else if (nb < 0) 17 | { 18 | ft_putchar('-'); 19 | nb *= -1; 20 | } 21 | if (nb > 9) 22 | ft_putnbr(nb / 10); 23 | ft_putchar(nb % 10 + '0'); 24 | } 25 | 26 | /* 27 | ** a ^= a is equivalent to a = 0 28 | */ 29 | 30 | int main(void) 31 | { 32 | int a = 5; 33 | 34 | ft_putnbr(a); 35 | a ^= a; 36 | ft_putnbr(a); 37 | return (0); 38 | } 39 | -------------------------------------------------------------------------------- /1.6_binary_gap.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | A binary gap within a positive integer N is any maximal sequence of consecutive zeros that is surrounded by ones at both ends in the binary representation of N. 4 | 5 | For example, number 9 has binary representation 1001 and contains a binary gap of length 2. The number 529 has binary representation 1000010001 and contains two binary gaps: one of length 4 and one of length 3. The number 20 has binary representation 10100 and contains one binary gap of length 1. The number 15 has binary representation 1111 and has no binary gaps. The number 32 has binary representation 100000 and has no binary gaps. 6 | 7 | Write a function: 8 | 9 | that, given a positive integer N, returns the length of its longest binary gap. The function should return 0 if N doesn't contain a binary gap. 10 | 11 | For example, given N = 1041 the function should return 5, because N has binary representation 10000010001 and so its longest binary gap is of length 5. Given N = 32 the function should return 0, because N has binary representation '100000' and thus no binary gaps. 12 | 13 | Write an efficient algorithm for the following assumptions: 14 | 15 | N is an integer within the range 1 to INT_MAX 16 | 17 | */ 18 | #include 19 | 20 | void ft_putchar(char c) 21 | { 22 | write(1, &c, 1); 23 | } 24 | 25 | void ft_putnbr(int nb) 26 | { 27 | if (nb == -2147483648) 28 | { 29 | ft_putchar('-'); 30 | ft_putchar('2'); 31 | nb = 147483648; 32 | } 33 | else if (nb < 0) 34 | { 35 | ft_putchar('-'); 36 | nb *= -1; 37 | } 38 | if (nb > 9) 39 | ft_putnbr(nb / 10); 40 | ft_putchar(nb % 10 + '0'); 41 | } 42 | 43 | static int solution(int N) { 44 | int count; 45 | int max = 0; 46 | 47 | while (N) // we go through each digit of the number, representing it as a binary figure like 9 becomes 0b1001 48 | { 49 | if (N & 1) // if the number is odd, same as if (N % 2 == 1) 50 | { 51 | count = 0; // starting the counter 52 | while ((N >>= 1) && (~N & 1)) // we divide by 2 (the right shift '>>=' is equivalent to '/= 2') and then check the N is not odd (even) by toggling its bits with '~'. Hence the last digit was 0 in a binary representation then it would become 1. 53 | ++count; // increase the counter by 1, same as count = count + 1; 54 | if (count > max) 55 | max = count; // if our counter is bigger than the previously 56 | // stored maximum it becomes the new maximum, to handle case such as 0b10000010001 57 | } 58 | else 59 | N >>= 1; // if N is even then we divide N per 2 to go through the number. Example: If we have '10 = 0b1010' so divided by 2 (right shift >>) it becomes '0b101 = 5' 60 | } 61 | return max; 62 | } 63 | 64 | int main(void) 65 | { 66 | int a = 9; 67 | 68 | ft_putnbr(solution(a)); 69 | 70 | return (0); 71 | } 72 | -------------------------------------------------------------------------------- /1.7_align_size.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ** 1.7 : Using bit operation to align a size 3 | **********************************************************************/ 4 | 5 | #include 6 | #include 7 | 8 | /* 9 | ** we can use a combination of left and right shifts using the power of two 10 | ** align. If align = 5 we will align on 2^5 = 32 bytes 11 | ** Constraint : align < 32 12 | */ 13 | 14 | size_t ft_align_power_of_two(size_t size, size_t align) 15 | { 16 | return (((size + (1 << align) - 1) >> align) << align); 17 | } 18 | 19 | /* 20 | ** equivalently we can use a mask 21 | ** if size is 37 and we add the mask (31) we get 68. 22 | ** Then we ask to keep only the bits above the 5th since '~mask' toggle bits 23 | ** will becomes 0b1...10000 24 | ** Constraint : mask must be a power of 2 - 1 25 | */ 26 | 27 | size_t ft_align_mask(size_t size, size_t mask) 28 | { 29 | return ((size + mask) & ~mask); 30 | } 31 | 32 | int main(void) 33 | { 34 | int n = 37; 35 | printf("%lu\n", ft_align_power_of_two(n, 5)); // 2^5 = 32 36 | printf("%lu\n", ft_align_mask(n, 0x1f)); // 0x1f + 1 = 0x20 = 32 37 | return (0); 38 | } 39 | 40 | /* 41 | Resulting assembly: 42 | 43 | ft_align_power_of_two(unsigned long long, unsigned long long): 44 | mov rcx, rsi 45 | mov eax, 1 46 | sal eax, cl 47 | cdqe 48 | lea rax, [rdi-1+rax] 49 | shr rax, cl 50 | sal rax, cl 51 | ret 52 | 53 | ft_align_mask(unsigned long long, unsigned long long): 54 | lea rax, [rdi+rsi] 55 | not rsi 56 | and rax, rsi 57 | ret 58 | 59 | You can hence witness that the function aligning using the mask is much more optimized !! 60 | */ 61 | -------------------------------------------------------------------------------- /1.8_reverse_bits_template.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | T reverse_bits(T n) { 7 | short bits = sizeof(n) * 8; 8 | T mask = ~T(0); // equivalent to uint32_t mask = 0b11111111111111111111111111111111; 9 | 10 | while (bits >>= 1) { 11 | mask ^= mask << (bits); // will convert mask to 0b00000000000000001111111111111111; 12 | n = (n & ~mask) >> bits | (n & mask) << bits; // we need ~mask for the upper part and mask for the lower part 13 | } 14 | 15 | return n; 16 | } 17 | 18 | template 19 | void print_binary(T n) 20 | { 21 | T mask = 1UL << ((sizeof(n) * 8) - 1); // will set the most significant bit 22 | for(; mask != 0; mask >>= 1) putchar('0' | !!(n & mask)); 23 | putchar('\n'); 24 | } 25 | 26 | int main() { 27 | uint32_t n = 12; 28 | print_binary(n); 29 | n = reverse_bits(n); 30 | print_binary(n); 31 | unsigned char c = 'a'; 32 | print_binary(c); 33 | c = reverse_bits(c); 34 | print_binary(c); 35 | uint16_t s = 12; 36 | print_binary(s); 37 | s = reverse_bits(s); 38 | print_binary(s); 39 | uint64_t l = 12; 40 | print_binary(l); 41 | l = reverse_bits(l); 42 | print_binary(l); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /1.9_reverse_bits_assembly.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | // Compile with g++ -masm=intel a.cpp && ./a.out 7 | 8 | template 9 | T reverse_bits(T n) { 10 | short bits = sizeof(n) * 8; 11 | T mask = ~T(0); // equivalent to uint32_t mask = 0b11111111111111111111111111111111; 12 | 13 | while (bits >>= 1) { 14 | mask ^= mask << (bits); // will convert mask to 0b00000000000000001111111111111111; 15 | n = (n & ~mask) >> bits | (n & mask) << bits; // divide and conquer 16 | } 17 | 18 | return n; 19 | } 20 | 21 | 22 | unsigned char reverse_bits1(unsigned char c) { 23 | __asm__ __volatile__ (R"( 24 | or cx, 8 25 | myloop: 26 | ror di 27 | adc ax, ax 28 | dec cx 29 | jnz short myloop 30 | ;)"); 31 | } 32 | 33 | uint32_t reverse_bits2(uint32_t a) { 34 | __asm__ __volatile__ (R"( 35 | mov ecx, 32 36 | loop2: 37 | shr edi 38 | rcl eax 39 | dec cl 40 | jnz short loop2 41 | ;)"); 42 | } 43 | 44 | 45 | uint32_t reverse_bits4(uint32_t n) { 46 | // uint32_t a = n; 47 | // add .intel_syntax 48 | // mov edi, DWORD PTR [rbp-8] 49 | __asm__ __volatile__ (R"( 50 | bswap edi 51 | mov edx, edi 52 | shr edi, 4 53 | sal edx, 4 54 | and edi, 252645135 55 | and edx, -252645136 56 | or edi, edx 57 | mov edx, edi 58 | sal edi, 2 59 | shr edx, 2 60 | and edi, -858993460 61 | and edx, 858993459 62 | or edx, edi 63 | mov eax, edx 64 | add edx, edx 65 | shr eax 66 | and edx, -1431655766 67 | and eax, 1431655765 68 | or eax, edx 69 | 70 | ;)"); 71 | 72 | //mov DWORD PTR [rbp-8], eax 73 | //return a; 74 | } 75 | 76 | 77 | uint32_t reverse_bits5(uint32_t n) { 78 | uint32_t a = n; 79 | 80 | __asm__ __volatile__ (R"( 81 | xor eax, eax 82 | inc eax 83 | myloop3: 84 | shr edi, 1 85 | adc eax, eax 86 | jnc short myloop3 87 | ;)"); 88 | } 89 | 90 | 91 | template 92 | void print_binary(T n) 93 | { T mask = 1UL << ((sizeof(n) * 8) - 1); // will set the most significant bit 94 | for(; mask != 0; mask >>= 1) putchar('0' + !!(n & mask)); 95 | putchar('\n'); 96 | } 97 | 98 | int main() { 99 | unsigned int n = 12534534U | 1U << 31; 100 | 101 | print_binary(n); 102 | unsigned int o = reverse_bits5(n); 103 | print_binary(o); 104 | n = reverse_bits(n); 105 | print_binary(n); 106 | 107 | /* 108 | uint32_t n = 12; 109 | print_binary(n); 110 | n = reverse_bits(n); 111 | print_binary(n); 112 | unsigned char c = 'a'; 113 | print_binary(c); 114 | c = reverse_bits(c); 115 | print_binary(c); 116 | uint16_t s = 12; 117 | print_binary(s); 118 | s = reverse_bits(s); 119 | print_binary(s); 120 | uint64_t l = 12; 121 | print_binary(l); 122 | l = reverse_bits(l); 123 | print_binary(l);*/ 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /2.0_bsr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include // for rand() 8 | #include // for clock() 9 | #include 10 | #include // for DBL_MAX 11 | #include // for intrinsics (function that use powerful underlying assembly instruction) 12 | #pragma intrinsic(bit_scan_reverse) 13 | // g++ -std=c++17 -masm=intel highestSetBit.cpp && ./a.out 14 | #include 15 | 16 | 17 | //#define F(x) &uint8_t ()(uint32_t) ("highestSetBitIndex".append('x')) 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | //#include 25 | 26 | 27 | using namespace std; 28 | using namespace std::chrono; 29 | 30 | /******************************************************************************/ 31 | /* Helpers */ 32 | /******************************************************************************/ 33 | 34 | //uint32_t highestSetBitOnly( uint32_t n ) __attribute__((optimize("-O3"))); 35 | 36 | uint8_t onPurposeSlowFunction(uint32_t n) 37 | { 38 | return sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) *sqrt(n * n) *sqrt(n * n) *sqrt(n * n) * sqrt(n * n) \ 39 | * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) *sqrt(n * n) *sqrt(n * n) *sqrt(n * n) * sqrt(n * n) 40 | * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) * sqrt(n * n) *sqrt(n * n) *sqrt(n * n) *sqrt(n * n) * sqrt(n * n); 41 | } 42 | 43 | void int_to_bin(int num) { 44 | char str[9] = {0}; 45 | int i; 46 | for (i=7; i>=0; i--) { 47 | str[i] = (num&1)?'1':'0'; 48 | num >>= 1; 49 | } 50 | printf("%s\n", str); 51 | } 52 | 53 | uint8_t exampleFunctionForInlineAssembly(uint32_t n) // undefined behavior if n == 0 54 | { 55 | uint8_t a = 0; 56 | __asm__ __volatile__ (R"( 57 | .intel_syntax noprefix 58 | bsr eax, edi 59 | .att_syntax noprefix 60 | )" 61 | // "mov %%edx, %1\n\t" 62 | "mov %0, %%al\n\t" 63 | :[a]"=r" (a) 64 | // :[n]"r" (n) 65 | ); 66 | return a; 67 | 68 | } 69 | 70 | 71 | uint8_t highestSetBitIndex100(uint32_t n) // undefined behavior if n == 0 72 | { 73 | uint8_t a = 0; 74 | __asm__ __volatile__ (R"( 75 | .intel_syntax noprefix 76 | bsr eax, edi 77 | .att_syntax noprefix 78 | )" 79 | // "mov %%edx, %1\n\t" 80 | "mov %0, %%al\n\t" 81 | :[a]"=r" (a) 82 | // :[n]"r" (n) 83 | ); 84 | return a; 85 | 86 | } 87 | 88 | 89 | /******************************************************************************/ 90 | /* Functions Test ******************************/ 91 | /******************************************************************************/ 92 | 93 | uint32_t lowestSetBitOnly(uint32_t n) 94 | { 95 | return n &= -n ; 96 | } 97 | 98 | void propagateBits(uint32_t *n) { 99 | *n |= *n >> 1; 100 | *n |= *n >> 2; 101 | *n |= *n >> 4; 102 | *n |= *n >> 8; 103 | *n |= *n >> 16; 104 | } 105 | 106 | uint32_t highestSetBitOnly(uint32_t n) 107 | { 108 | propagateBits(&n); 109 | return n - (n >> 1); 110 | } 111 | 112 | uint32_t vsNextPowerOfTwo(uint32_t value) 113 | { 114 | uint32_t n = highestSetBitOnly(value); 115 | return n << (!!(value ^ n)); // it's over 9000! 116 | } 117 | 118 | uint8_t highestSetBitIndex1(uint32_t n) 119 | { 120 | uint8_t r = 0; 121 | while (n >>= 1) 122 | r++; 123 | return r; 124 | } 125 | 126 | uint8_t highestSetBitIndex2(uint32_t n) { 127 | return (uint8_t)(log(n) / log(2)); 128 | } 129 | 130 | uint8_t highestSetBitIndex3(uint32_t b) 131 | { 132 | static const uint32_t deBruijnMagic = 0x06EB14F9; 133 | static const uint8_t deBruijnTable[64] = { 134 | 0, 0, 0, 1, 0, 16, 2, 0, 29, 0, 17, 0, 0, 3, 0, 22, 135 | 30, 0, 0, 20, 18, 0, 11, 0, 13, 0, 0, 4, 0, 7, 0, 23, 136 | 31, 0, 15, 0, 28, 0, 0, 21, 0, 19, 0, 10, 12, 0, 6, 0, 137 | 0, 14, 27, 0, 0, 9, 0, 5, 0, 26, 8, 0, 25, 0, 24, 0, 138 | }; 139 | return deBruijnTable[(highestSetBitOnly(b) * deBruijnMagic) >> 26]; 140 | } 141 | 142 | uint8_t highestSetBitIndex4(uint32_t n) // undefined behavior if n == 0 143 | { 144 | __asm__ __volatile__ (R"( 145 | .intel_syntax noprefix 146 | bsr eax, edi 147 | .att_syntax noprefix 148 | )" 149 | ); 150 | } 151 | 152 | uint8_t highestSetBitIndex5(uint32_t n) 153 | { 154 | return _bit_scan_reverse(n); // undefined behavior if n == 0 155 | } 156 | 157 | 158 | uint8_t highestSetBitIndex6(uint32_t n) 159 | { 160 | return 31 - __builtin_clz(n); // undefined behavior if n == 0 161 | } 162 | 163 | 164 | uint8_t highestSetBitIndex7(uint32_t n) // undefined behavior if n == 0 165 | { 166 | __asm__ __volatile__ (R"(.intel_syntax noprefix 167 | lzcnt ecx, edi 168 | mov eax, 31 169 | sub eax, ecx 170 | .att_syntax noprefix 171 | )"); 172 | } 173 | 174 | uint8_t highestSetBitIndex8(uint32_t b) 175 | { 176 | static const uint32_t Magic = (uint32_t) 0x07C4ACDD; 177 | 178 | static const int BitTable[32] = { 179 | 0, 9, 1, 10, 13, 21, 2, 29, 180 | 11, 14, 16, 18, 22, 25, 3, 30, 181 | 8, 12, 20, 28, 15, 17, 24, 7, 182 | 19, 27, 23, 6, 26, 5, 4, 31, 183 | }; 184 | propagateBits(&b); 185 | 186 | return BitTable[(b * Magic) >> 27]; 187 | } 188 | 189 | /* 190 | ** credit: https://sites.google.com/site/sydfhd/articles-tutorials/de-bruijn-sequence-generator 191 | */ 192 | 193 | uint8_t highestSetBitIndex9(uint32_t b) 194 | { 195 | static const uint8_t u = 0; 196 | static const uint8_t BitTable[64] = { 197 | 2, u, u, u, 9, u, 29, 5, 198 | u, u, 3, u, u, u, 21, u, 199 | u, 18, 10, u, 23, 13, 30, u, 200 | 6, u, 27, 1, u, u, u, 4, 201 | u, u, 20, u, 17, 22, 12, u, 202 | 26, u, u, u, 19, 16, 11, 25, 203 | u, u, 15, 24, 14, u, 31, u, 204 | u, u, 7, u, u, 8, 28, u, 205 | }; 206 | 207 | propagateBits(&b); 208 | b += (b << 3); // Multiply by 9 209 | b += (b << 4); // Multiply by 17 210 | /* b = (b << 5) - b; // Multiply by 31 211 | b = (b << 17) - b;// Multiply by 131071*/ 212 | b -= (b << 5); // Multiply by 31 213 | b -= (b << 17);// Multiply by 131071 214 | return BitTable[b >> 26]; 215 | } 216 | 217 | /******************************************************************************/ 218 | /* Benchmark Main */ 219 | /******************************************************************************/ 220 | #define N 10000 221 | #define BATTLE_NB 10000 222 | 223 | 224 | 225 | double benchmark(uint8_t (*f)(uint32_t)) { 226 | auto start = high_resolution_clock::now(); 227 | uint8_t a = 0; 228 | 229 | for (int i{}; i != N; ++i) 230 | a |= f(rand()); 231 | 232 | auto stop = high_resolution_clock::now(); 233 | double elapsedTime = duration_cast(stop - start).count(); 234 | // std::cerr << "Duration: " << duration << " ms\n"; 235 | return elapsedTime; 236 | } 237 | 238 | double overHead(uint8_t (*f)(uint32_t)) { 239 | auto start = high_resolution_clock::now(); 240 | uint8_t a = 0; 241 | 242 | for (int i{}; i != N; ++i) 243 | a |= rand(); 244 | 245 | auto stop = high_resolution_clock::now(); 246 | double elapsedTime = duration_cast(stop - start).count(); 247 | // std::cerr << "Duration: " << duration << " ms\n"; 248 | return elapsedTime; 249 | } 250 | 251 | int main(void) { 252 | srand (time (NULL)); 253 | uint64_t simulationsCount = 0; 254 | uint8_t (*func_ptr[])(uint32_t) = {&onPurposeSlowFunction, \ 255 | &highestSetBitIndex1, &highestSetBitIndex2, &highestSetBitIndex3, \ 256 | &highestSetBitIndex4, &highestSetBitIndex5, &highestSetBitIndex6, \ 257 | &highestSetBitIndex7, &highestSetBitIndex8, &highestSetBitIndex9}; 258 | int len = sizeof(func_ptr) / sizeof(void*); 259 | 260 | #ifdef __DEBUG__ 261 | for (uint32_t a = UINT_MAX; a > UINT_MAX - 100; a--) { 262 | //cout << endl << "Testing with: " << a << endl; 263 | uint32_t res = (uint32_t)func_ptr[1](a); 264 | for (int i = 2; i < len; i++) { 265 | 266 | uint32_t cur =(uint32_t)func_ptr[i](a); 267 | if (res != cur) 268 | printf("error with function %u returning %u instead of %u\n", i, cur, res); 269 | //cout << (uint32_t)(func_ptr[i](a)) << endl; 270 | //cout << (uint32_t)(highestSetBitIndex1(a)) << endl; 271 | } 272 | } 273 | return 0; 274 | #endif 275 | 276 | int battle = BATTLE_NB; 277 | simulationsCount = (N * battle) / 1000000.0f; // million of simulations 278 | double elapsedTime[len] = {}; 279 | int score[len] = {}; 280 | 281 | while (battle--) { 282 | int currentScore = 0; 283 | int lowestLatencyIndex = 0; 284 | double lowestLatency = numeric_limits::max(); 285 | double currentElapsedTime = 0; 286 | for (int i = 1; i < len; i++) { 287 | currentElapsedTime = benchmark(func_ptr[i]); 288 | currentElapsedTime -= overHead(func_ptr[i]); 289 | if (currentElapsedTime < lowestLatency) { 290 | lowestLatency = currentElapsedTime; 291 | lowestLatencyIndex = i; 292 | } 293 | elapsedTime[i] += currentElapsedTime; 294 | } 295 | //printf("winner %d \n", lowestLatencyIndex); 296 | score[lowestLatencyIndex]++; 297 | } 298 | int winner = 0; 299 | int bestScore = 0; 300 | for (int i = 0; i < len; i++) { 301 | elapsedTime[i] /= N * 1000; 302 | if (score[i] > bestScore) 303 | { 304 | bestScore = score[i]; 305 | winner = i; 306 | } 307 | } 308 | char color[13]; // https://misc.flogisoft.com/bash/tip_colors_and_formatting 309 | strncpy(color, "\e[1m\e[96m", 13); //bold and cyan 310 | printf("\n%s%lu million simulations result:\n\e[0m", color, simulationsCount); 311 | for (int i = 1; i < len; ++i) { 312 | color[0] = '\0'; 313 | if (i == winner) // \033[5m 314 | strncpy(color, "\e[1m\e[5m\e[92m", 13); // bold, blink and green 315 | printf("\tFunction %2d scored %6d with an average time of %s%03.1lf\e[0m ms\n", i, score[i], color, elapsedTime[i]); 316 | } 317 | putchar('\n'); 318 | 319 | return 0; 320 | } 321 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | I created these files as a way to better understand bitwise operators and practical use 3 | When developers are challenged by memory limitation or have high speed requirement as for 4 | embedded systems (FR : systemes embarques) like drones, bitwise operators come in handy. 5 | 6 | * 1.0 Introduction to Bitwises operators. 7 | * 1.1 Learn how to print (display) bits. 8 | * 1.2 Learn how to reverse a byte. 9 | * 1.3 Check if a number is power of 2 or not. 10 | * 1.4 Learn how to use bitwise operators to save memory when parsing. 11 | * 1.5 Learn how to clear all bits. 12 | * 1.6 Check the binary gap within a positive integer N is any maximal sequence of consecutive zeros that is surrounded by ones at both ends in the binary representation of N. 13 | * 1.7 Learn how use bit shifts and bit mask to align the size of a given number. 14 | 15 | ### Reverse bits inside Byte(s) 16 | 17 | *There are many ways to reverse bits depending on what you mean the "simplest way".* 18 | 19 | --- 20 | ### Reverse by Rotation 21 | Probably the most logical, consists in rotating the byte while applying a mask on the first bit ```(n & 1)```: 22 | ```c++ 23 | unsigned char reverse_bits(unsigned char b) 24 | { 25 | unsigned char r = 0; 26 | unsigned byte_len = 8; 27 | 28 | while (byte_len--) { 29 | r = (r << 1) | (b & 1); 30 | b >>= 1; 31 | } 32 | return r; 33 | } 34 | ``` 35 | 36 | 1) As the length of an unsigner char is 1 byte, which is equal to 8 bits, it means we will scan each bit ```while (byte_len--)``` 37 | 38 | 2) We first check if b as a bit on the extreme right with ```(b & 1)```; 39 | if so we set bit 1 on r with ```|``` and move it just 1 bit to the left by 40 | multiplying r by 2 with ```(r << 1)``` 41 | 42 | 3) Then we divide our unsigned char b by 2 with ```b >>=1``` to erase 43 | the bit located at the extreme right of variable b. 44 | As a reminder, b >>= 1; is equivalent to b /= 2; 45 | 46 | --- 47 | ### Reverse in One Line 48 | 49 | This solution is attributed to [Rich Schroeppel in the Programming Hacks section](http://www.inwap.com/pdp10/hbaker/hakmem/hakmem.html) 50 | 51 | ```c++ 52 | unsigned char reverse_bits3(unsigned char b) 53 | { 54 | return (b * 0x0202020202ULL & 0x010884422010ULL) % 0x3ff; 55 | } 56 | ``` 57 | 58 | 1) The multiply operation (b * 0x0202020202ULL) creates five separate copies of the 8-bit byte pattern to fan-out into a 64-bit value. 59 | 60 | 2) The AND operation (& 0x010884422010ULL) selects the bits that are in the 61 | correct (reversed) positions, relative to each 10-bit groups of bits. 62 | 63 | 3) Together the multiply and the AND operations copy the bits from the original 64 | byte so they each appear in only one of the 10-bit sets. 65 | The reversed positions of the bits from the original byte coincide with their 66 | relative positions within any 10-bit set. 67 | 68 | 4) The last step (% 0x3ff), which involves modulus division by 2^10 - 1 69 | has the effect of merging together each set of 10 bits 70 | (from positions 0-9, 10-19, 20-29, ...) in the 64-bit value. 71 | They do not overlap, so the addition steps underlying the modulus 72 | division behave like OR operations. 73 | 74 | --- 75 | ### Divide and Conquer Solution 76 | 77 | ```c++ 78 | unsigned char reverse(unsigned char b) { 79 | b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; 80 | b = (b & 0xCC) >> 2 | (b & 0x33) << 2; 81 | b = (b & 0xAA) >> 1 | (b & 0x55) << 1; 82 | return b; 83 | } 84 | ``` 85 | This is the most upvoted answer and despite some explanations, I think that for most people it feels difficult to visualize whats 0xF0, 0xCC, 0xAA, 0x0F, 0x33 and 0x55 truly means. 86 | 87 | It does not take advantage of '0b' which is a [GCC extension](https://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html) and is included since the C++14 standard, release in December 2014, so a while after this answer dating from April 2010 88 | 89 | > Integer constants can be written as binary constants, consisting of a sequence of ‘0’ and ‘1’ digits, prefixed by ‘0b’ or ‘0B’. This is particularly useful in environments that operate a lot on the bit level (like microcontrollers). 90 | 91 | Please check below code snippets to remember and understand even better this solution where we move half by half: 92 | 93 | 94 | ```c++ 95 | unsigned char reverse(unsigned char b) { 96 | b = (b & 0b11110000) >> 4 | (b & 0b00001111) << 4; 97 | b = (b & 0b11001100) >> 2 | (b & 0b00110011) << 2; 98 | b = (b & 0b10101010) >> 1 | (b & 0b01010101) << 1; 99 | return b; 100 | } 101 | ``` 102 | 103 | NB: The ```>> 4``` is because there are 8 bits in 1 byte, which is an unsigned char so we want to take the other half, and so on. 104 | 105 | We could easily apply this solution to 4 bytes with only two additional lines and following the same logic. Since both mask complement each other we can even use ~ in order to switch bits and saving some ink: 106 | 107 | ```c++ 108 | uint32_t reverse_integer_bits(uint32_t b) { 109 | uint32_t mask = 0b11111111111111110000000000000000; 110 | b = (b & mask) >> 16 | (b & ~mask) << 16; 111 | mask = 0b11111111000000001111111100000000; 112 | b = (b & mask) >> 8 | (b & ~mask) << 8; 113 | mask = 0b11110000111100001111000011110000; 114 | b = (b & mask) >> 4 | (b & ~mask) << 4; 115 | mask = 0b11001100110011001100110011001100; 116 | b = (b & mask) >> 2 | (b & ~mask) << 2; 117 | mask = 0b10101010101010101010101010101010; 118 | b = (b & mask) >> 1 | (b & ~mask) << 1; 119 | return b; 120 | } 121 | ``` 122 | 123 | --- 124 | ### [C++ Only] Reverse Any Unsigned ! (Template) 125 | 126 | The above logic can be summarized with a loop that would work on any type of unsigned: 127 | ```c++ 128 | template 129 | T reverse_bits(T n) { 130 | short bits = sizeof(n) * 8; 131 | T mask = ~T(0); // equivalent to uint32_t mask = 0b11111111111111111111111111111111; 132 | 133 | while (bits >>= 1) { 134 | mask ^= mask << (bits); // will convert mask to 0b00000000000000001111111111111111; 135 | n = (n & ~mask) >> bits | (n & mask) << bits; // divide and conquer 136 | } 137 | 138 | return n; 139 | } 140 | ``` 141 | 142 | Try it yourself with inclusion of above function: 143 | ```c++ 144 | #include 145 | #include 146 | #include 147 | 148 | template 149 | void print_binary(T n) 150 | { T mask = 1ULL << ((sizeof(n) * 8) - 1); // will set the most significant bit 151 | for(; mask != 0; mask >>= 1) putchar('0' | !!(n & mask)); 152 | putchar('\n'); 153 | } 154 | 155 | int main() { 156 | uint32_t n = 12; 157 | print_binary(n); 158 | n = reverse_bits(n); 159 | print_binary(n); 160 | unsigned char c = 'a'; 161 | print_binary(c); 162 | c = reverse_bits(c); 163 | print_binary(c); 164 | uint16_t s = 12; 165 | print_binary(s); 166 | s = reverse_bits(s); 167 | print_binary(s); 168 | uint64_t l = 12; 169 | print_binary(l); 170 | l = reverse_bits(l); 171 | print_binary(l); 172 | return 0; 173 | } 174 | ``` 175 | 176 | --- 177 | ### Bonus, Assembly code, refer to 1.9 178 | ```asm 179 | mov cx, 8 ; we will reverse the 8 bits contained in one byte 180 | loop: ; while loop 181 | ror di ; rotate `di` (containing value of the first argument of callee function) to the Right in a non-destructive manner 182 | adc ax, ax ; shift `ax` left and add the carry, the carry is equal to 1 if one bit was rotated from 0b1 to MSB from previous operation 183 | dec cx ; Decrement cx 184 | jnz short loop ; Jump if cx register Not equal to Zero else end loop and return ax 185 | ``` 186 | 187 | ## Contact & contribute 188 | To contact me and helping me to (fix bugs || improve) 42-Bitwises_Operators, feel free to e-mail me at **angavrel at student dot 42 dot fr** 189 | -------------------------------------------------------------------------------- /bitwise.h: -------------------------------------------------------------------------------- 1 | #ifndef BITWISE_H 2 | # define BITWISE_H 3 | 4 | #include 5 | 6 | /* 7 | ** Trick 1.4 8 | */ 9 | 10 | # define FLAG_A 1 11 | # define FLAG_B 2 12 | # define FLAG_C 4 13 | # define FLAG_D 8 14 | 15 | #endif --------------------------------------------------------------------------------