※ 引述《oncemore (枪不能这样打)》之铭言:
: 给一些不会做circular shift 的同学参考,当然这不是唯一解
: 假设一个数字(number),经过运算之后会得到一个数值(result)
: 你现在的任务就是要把题目给的result 转换成原本的number。
: int number;
: int number_mod;
: int result;
: int shift;
: not 的部分:
: number = ~number;
: result = number + 256;
: (Ex.)以范例测资1来说,
: df(16进位) = 223 (10进位)...我们要的result是223
: number = 32;(要得到223的解)
: number = ~number; (此时number == -33 )
: result = number + 256; (result == 223)
: 所以我们找到32经过not的运算后可以得到df,也就是223,
: 所以要把(ASCII码)32对应到的字符印出来。
之所以这样的原因, 是因为 int 占了 4 个 bytes, 而我们输入的数值只有 0-255
number:00 00 00 df
做了 not 运算之后会变成这样
~number:ff ff ff 20
而 256 正好是 00 00 01 00, 所以加到 ~number 上刚好让前三个 ff 溢位变成 0 回来
实际上我们可以很直观的想:我们要的只是最后 8 个 bit
所以 (~number) & 0xff 就好了, 甚至你把 number 存成一个 unsigned char,
那 ~number 自然会是 0x20
不知道想到 (~number) + 256 的原因是不是从 (-a) = (~a) + 1 这样来的呢:)
: 这里你可以用 number 从 0 跑到 255 去找出对应的值,
: 找到了之后就记录起来并 break 掉。
反过来想,一个数字 not 两次之后跟没 not 一样
输入的是 not 过的数字,要找 not 之前的数字,再 not 一次就好,就变回来了
: leftR 的部分:(假设要转的位数是shift位)
: number = number * pow( 2 , shift%8 ); (你要include <math.h> )
: number_mod = number % 256;
: number = number / 256;
: result = number + number_mod;
: (Ex.)以范例测资1来说,
: leftR 3,向左侧移三位。
: 1(16进位) = 1(10进位)...我们要的result是1
: shift = 3;
: number = 32;(要得到1的解)
: number = number * pow(2,shift%8); (number == 32 * 8 == 256 )
: number_mod = number % 256;(number_mod == 0 )
: number = number / 256;(number == 1 )
: result = number + number_mod; (result == 1 + 0 == 1 )
: 于是我们找到了32可以经过左移三位后得到1
: rightR 的部分:(假设要转的位数是shift位)
: number = number * 256;
: number = number / pow( 2 , shift%8 );
: number_mod = number % 256;
: number = number / 256;
: result = number + number_mod;
: (Ex.)以范例测资1来说,
: rightR 4,向右侧移四位。
: 2(16进位) = 2(10进位)...我们要的result是2
: shift = 4;
: number = 32(要得到2的解)
: number = number * 256; (number == 8192)
: number = nubmer / pow ( 2 , 4 ); (number == 512)
: number_mod = number % 256; (number_mod == 0)
: number = number / 256; (number == 2)
: result = number + number_mod; (result = 2)
: 于是我们找到了32可以经过右移四位后得到2
这边我不太确定 pow 是不是那个 pow 函式? 可是我怎么记得那个 pow 是浮点数的@@
其实可以这样想:
01234567
ror 1 70123456
ror 2 67012345
...类推
首先考虑只向右轮旋一个位元的情形
他可以直接被拆解成 0123456 右移一位, or 7 左移 7 位
所以我们可以写出如下的程式:
output = (input >> 1) | ((input << 7) & 0xff)
0123456右移一位 or 左移 遮罩掉我们不要的位元(突出去的)
同理,若移 2 位也是类似
output = (input >> 2) | ((input << 6) & 0xff)
观察规律, 可以知道是类似 output = (input >> i) | ((input << (8 - i)) & 0xff)
的东西, 其中 i 是旋转的位数, 且 0 ≦ i < 8
当然轮旋了八次后与没轮旋也是一样的, 所以可以先把次数 mod 8
: 补充:对于left 和 right 的作法,
: 我是想像成16个bits在做运算
: 以上是我的作法,
: 请各位多多指教,谢谢。
p.s. 我个人在想位运算的时候 比较喜欢用两进位或十六进制来看 好像比较直觉XD
此外, << a 相当于乘上 2^a, >> a 则相当于除以 2^a (整数除法), 这都很方便使用