寻求无符号数右移向偶舍入函数的简洁等价实现
无符号数带舍入右移:向偶数舍入的简洁等价实现
背景与问题
对无符号数执行带舍入的右移操作时,已有以下可行实现:
// 向下舍入右移 unsigned rshift_round_down(unsigned x, unsigned a) { return x >> a; } // 向上舍入右移 unsigned rshift_round_up(unsigned x, unsigned a) { return (x >> a) + ((x & ((1U << a) - 1)) != 0); } // 中间值向上舍入右移 unsigned rshift_round_halfway(unsigned x, unsigned a) { if (a == 0) return x; return (x >> a) + ((x >> (a - 1)) & 1); } // 向偶数舍入右移(原实现) unsigned rshift_round_towards_even(unsigned x, unsigned a) { if (a == 0) return x; return (x >> a) + ((x >> (a - ((x & ((1U << a) - 1)) != 1 << (a - 1)))) & 1); }
现询问:是否存在更简洁但功能完全等价的rshift_round_towards_even实现?
注:参数a的取值范围为 0 <= a && a < sizeof(unsigned) * 8,无需支持超出该范围的取值。
示例输入输出
rshift_round_towards_even(60, 2) == 15rshift_round_towards_even(61, 2) == 15rshift_round_towards_even(62, 2) == 16(中间值向偶数舍入,结果向上)rshift_round_towards_even(63, 2) == 16rshift_round_towards_even(64, 2) == 16rshift_round_towards_even(65, 2) == 16rshift_round_towards_even(66, 2) == 16(中间值向偶数舍入,结果向下)rshift_round_towards_even(67, 2) == 17rshift_round_towards_even(68, 2) == 17rshift_round_towards_even(69, 2) == 17rshift_round_towards_even(70, 2) == 18(中间值向偶数舍入,结果向上)rshift_round_towards_even(71, 2) == 18rshift_round_towards_even(72, 2) == 18rshift_round_towards_even(73, 2) == 18
简洁等价实现
有,基于向偶数舍入的核心规则:
- 若舍去部分大于
2^(a-1),则进位; - 若舍去部分小于
2^(a-1),则不进位; - 若舍去部分恰好等于
2^(a-1)(中间值),仅当右移后的结果为奇数时进位,否则不进位。
易读版实现
unsigned rshift_round_towards_even(unsigned x, unsigned a) { if (a == 0) return x; const unsigned mask = (1U << a) - 1; const unsigned lower_bits = x & mask; // 被舍去的低a位 const unsigned upper_bits = x >> a; // 右移后的高位部分 // 判断是否需要进位 const int need_round = (lower_bits > (1U << (a-1))) || (lower_bits == (1U << (a-1)) && (upper_bits & 1)); return upper_bits + need_round; }
紧凑位运算版
如果追求代码紧凑,可将逻辑合并为一行(可读性稍降,但功能完全等价):
unsigned rshift_round_towards_even(unsigned x, unsigned a) { return a ? (x >> a) + (((x >> (a-1)) & 1) & ((x & ((1U << a)-1)) != (1U << (a-1)) || ((x >> a) & 1))) : x; }
高效运算版
利用无符号数加法特性,还能写出更高效的实现:
unsigned rshift_round_towards_even(unsigned x, unsigned a) { if (a == 0) return x; const unsigned half = 1U << (a-1); const unsigned mask = (1U << a) - 1; // 先按中间值向上舍入,再修正中间值时的偶数舍入规则 return (x + half - 1) >> a - ((x & mask) == half && !((x >> a) & 1)); }
以上实现均与原函数功能完全一致,但代码更简洁、可读性更强。
内容的提问来源于stack exchange,提问作者pts
相关产品推荐
相关产品推荐

