是否存在使用模的表达式来进行向后回绕(“反向溢出")? [英] Is there an expression using modulo to do backwards wrap-around ("reverse overflow")?

查看:101
本文介绍了是否存在使用模的表达式来进行向后回绕(“反向溢出")?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于任何受 R = [ x y ]范围限制的整数输入 W W 相对于 R 的溢流"()是W % (y-x+1) + x.如果 W 超过 y ,则会导致回退.

For any whole number input W restricted by the range R = [x,y], the "overflow," for lack of a better term, of W over R is W % (y-x+1) + x. This causes it wrap back around if W exceeds y.

作为此原理的一个示例,假设我们迭代日历的月份:

As an example of this principle, suppose we iterate over a calendar's months:

int this_month = 5;
int next_month = (this_month + 1) % 12;

其中两个整数都在0到11之间(含0和11).因此,上面的表达式将整数钳位"到范围 R = [0,11].这种使用表达式的方法简单,优雅并且具有优势,因为它 省略了分支 .

where both integers will be between 0 and 11, inclusive. Thus, the expression above "clamps" the integer to the range R = [0,11]. This approach of using an expression is simple, elegant, and advantageous as it omits branching.

现在,如果我们想做同样的事情但倒退怎么办?以下表达式有效:

Now, what if we want to do the same thing, but backwards? The following expression works:

int last_month = ((this_month - 1) % 12 + 12) % 12;

但是太深奥了.怎样美化它?

but it's abstruse. How can it be beautified?

tl; dr -表达式((x-1) % k + k) % k可以进一步简化吗?

tl;dr - Can the expression ((x-1) % k + k) % k be simplified further?

注意:之所以指定C ++标记,是因为其他语言对模运算符的负操作数的处理方式不同.

推荐答案

您的表达式应为((x-1) + k) % k.这将正确地将x = 0环绕到11.通常,如果要退回多于1,则需要确保添加足够的量,以便模运算的第一个操作数为> = 0.

Your expression should be ((x-1) + k) % k. This will properly wrap x=0 around to 11. In general, if you want to step back more than 1, you need to make sure that you add enough so that the first operand of the modulo operation is >= 0.

这是C ++的实现:

int wrapAround(int v, int delta, int minval, int maxval)
{
  const int mod = maxval + 1 - minval;
  if (delta >= 0) {return  (v + delta                - minval) % mod + minval;}
  else            {return ((v + delta) - delta * mod - minval) % mod + minval;}
}

这还允许使用标记为0到11或1到12的月份,分别设置min_valmax_val.

This also allows to use months labeled from 0 to 11 or from 1 to 12, setting min_val and max_val accordingly.

由于这个答案非常受人欢迎,因此这是一个没有分支的改进版本,它还可以处理初始值v小于minval的情况.我保留另一个示例,因为它更易于理解:

Since this answer is so highly appreciated, here is an improved version without branching, which also handles the case where the initial value v is smaller than minval. I keep the other example because it is easier to understand:

int wrapAround(int v, int delta, int minval, int maxval)
{
  const int mod = maxval + 1 - minval;
  v += delta - minval;
  v += (1 - v / mod) * mod;
  return v % mod + minval;
}

剩下的唯一问题是minval是否大于maxval.随时添加断言.

The only issue remaining is if minval is larger than maxval. Feel free to add an assertion if you need it.

这篇关于是否存在使用模的表达式来进行向后回绕(“反向溢出")?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆