如何右移四舍五入到偶数

问题描述 投票:0回答:1

为了通过舍入对无符号值进行右移,以下函数对我有用:

unsigned rshift_round_down(unsigned x, unsigned a) {
  return x >> a;
}

unsigned rshift_round_up(unsigned x, unsigned a) {
  return (x >> a) + ((x & ((1 << a) - 1)) != 0);
}

unsigned rshift_round_halfway(unsigned x, unsigned a) {
  return (x >> a) + ((x >> (a - 1)) & 1);
}

unsigned rshift_round_towards_even(unsigned x, unsigned a) {
  return (x >> a) + ((x >> (a - ((x & ((1 << a) - 1)) != 1 << (a - 1)))) & 1);
}

是否有更简单但等效的 rshift_round_towards_even 实现?

输入和输出示例:

  • rshift_round_towards_even(60, 2) == 15
  • rshift_round_towards_even(61, 2) == 15
  • rshift_round_towards_even(62, 2) == 16(中间向偶数向上)
  • rshift_round_towards_even(63, 2) == 16
  • rshift_round_towards_even(64, 2) == 16
  • rshift_round_towards_even(65, 2) == 16
  • rshift_round_towards_even(66, 2) == 16(中间向偶数向下)
  • rshift_round_towards_even(67, 2) == 17
  • rshift_round_towards_even(68, 2) == 17
  • rshift_round_towards_even(69, 2) == 17
  • rshift_round_towards_even(70, 2) == 18(中间向偶数向上)
  • rshift_round_towards_even(71, 2) == 18
  • rshift_round_towards_even(72, 2) == 18
  • rshift_round_towards_even(73, 2) == 18
c rounding
1个回答
0
投票

现有代码存在问题

当 1 移入符号位时,

1 << a
未定义行为 (UB)。 使用
1u << a

rshift_round_halfway(x , 0)
是 UB,因为
(x >> (a - 1))
是负位移。

未经测试的替代品

rshift_round_towards_even()

也许有问题 - 稍后会评论 - GTG。

unsigned rshift_round_towards_even_alt(unsigned x, unsigned a) {
  unsigned shifted_lsbit_mask = 1u << a;
  unsigned bits_shifted_out_mask = shifted_lsbit_mask - 1u;
  unsigned bits_shifted_out = bits_shifted_out_mask & x;
  unsigned is_even = !(shifted_lsbit_mask & x);
  unsigned carry = (bits_shifted_out + is_even) > (lsbit_shifted_out_mask >> 1);
  return (x >> a) + carry;
}
© www.soinside.com 2019 - 2024. All rights reserved.