当我的数字从1开始而不是零时,我如何模数?

时间:2010-09-27 11:25:37

标签: modulo

我想这方面的解决方案非常简单,但我已经考虑了一段时间,但却找不到优雅的解决方案。

我有一系列数字,例如1..10 = (1,2,3,4,5,6,7,8,9,10),这是循环的,意味着最后一个之后的数字也是第一个(next(10)=1)。

对于范围内的给定数字i>0,我想计算下一个m - 和之前的m个数字。例如next(5,1)=6 next(10,1)=1 next(10,2)=2 prev(5,2)=3 prev(1,1)=10 prev(1,2)=9

对于next我可以(i+m)%n n,其中n=10是范围的长度(示例中为prev)。但对于{{1}}我找不到一个优雅的解决方案。

7 个答案:

答案 0 :(得分:30)

只需减去1并在之后加1。

在大多数编程语言中,您需要注意何时找到“上一个”值,因为对于负数,模数在这种情况下不能正常工作:它返回一个负数。

这是C / C ++版本:

int next(int i, int m, int n) { return (i + m - 1) % n + 1; }
int prev(int i, int m, int n) { return (i - m + n - 1) % n + 1; }

但是,在Perl模数中总是返回一个正值(至少当第二个操作数是一个正整数时)。基本上它做你想要的。因此,您可以编写以下内容并省略+ $_[2]

sub nxt { ($_[0] + $_[1] - 1) % $_[2] + 1; }
sub prv { ($_[0] - $_[1] - 1) % $_[2] + 1; }

答案 1 :(得分:6)

你的next = (i + m) % n无论如何都不对 - 在某些情况下它会返回零。

请改为尝试:

next(i, m) = ((i - 1) + m) % n + 1
prev(i, m) = ((i - 1) + n - m) % n + 1

实际上,取一个,然后找到正确的值,然后重新添加一个。

对于prev,请先添加n以确保您永远不会使用负数的模数

答案 2 :(得分:2)

next(i,m)previous(i,-m)之间有什么区别?没有!。我们走吧(i - 1 + n + m % n) % n + 1

$ perl -le 'sub gen {my $n = shift; return sub{ my ($i, $m) = @_; return ($i - 1 + $n + $m % $n) % $n + 1;};} $"=","; for my $n (2..5) { my $f = gen($n); print "$n: @{[map {$f->(1,$_)} -10 .. 10]}"}'
2: 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1
3: 3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2
4: 3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3
5: 1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1

答案 3 :(得分:1)

如果你不介意,首先要说几句话。

实现“上一步”功能的困惑来自于在正面和负面整数域中思考这个问题。从几何学的角度考虑它,如果你想象一个具有10个等间距点的圆,那么解决方案看起来像这样:

正如您正确指定的那样,给定范围[x..z],其范围为圆形,您可以找到下一个m-th number(i+m)%k where i belongs to [x..z]k是范围的长度

现在,对于“前一个”第m个成员。 可以通过计算(或更直观地表达,“到达”)前一个第m个数字位置(伪代码)来找到前一个数字:

prev(m, i) = (i + len(range) - m) % len(range)

例如,如果你取第10个的前一个,那么

prev(1,10) = (10+10-1)%10 = 19%10 = 9

前3号,数字5 = prev(3,5) = (5+10-3)%10 = 12%10 = 2。 Etcetera,etcetera。 非常简单,优雅,呵呵?

这里唯一需要注意的是if i == m,模数将为零,因此在next()和prev()函数中需要一个处理机制。

希望这有帮助, 雅各

答案 4 :(得分:1)

您可能会查看Tie::Cycle的来源,这是我创建的模块,用于遍历任意列表。

请记住,数字实际上只是代表某些东西的字形。如果你有这些字形的Perl列表,你仍然有一个从零开始的序列,因为你对列表索引进行了数学运算,而不是字形。当您选择了正确的列表索引时,可以使用该索引处的元素。

如果你想要非常大的列表或懒惰列表,你仍然可以这样做,但你只需要做更多的工作。

答案 5 :(得分:0)

我在R中有此解决方案:

pred <- function(n) n - 1L # cf. Pascal's pred
succ <- function(n) n + 1L # cf. Pascal's succ
`%mod1%` <- function(m, n) succ(pred(m) %% n) # modulo from 1
cat(-11:24 %mod1% 12) # test
# 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12

答案 6 :(得分:0)

假设你想从 1 映射到 n 而不是 0 映射到 n-1 例如 n=5,范围 1 到 x,结果 0 到 4,0mod5=0 1mod5=1, 2mod5=2... xmod5 结果 0 每当x=5*k。使用 ((x-1)mod5)+1,x 必须 >0。这将始终映射(计数)在 1 到 5 范围内,而不是 0 到 4。