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

发布于 2024-09-25 09:20:49 字数 558 浏览 0 评论 0原文

我想这个问题的解决方案很简单,但我已经思考了一段时间,但无法想出一个优雅的解决方案。

我有一个数字范围,例如 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 上一个(1,1)=10 上一个(1,2)=9

对于 next 我可以只采用 (i+m)%n 其中 n 是范围的长度 (n=10< /code> 在示例中)。但对于 prev 我找不到一个优雅的解决方案。

I guess the solution for this is quite simple, but I've been thinking about it for a while and couldn't come up with an elegant solution.

I have a range of numbers, e.g. 1..10 = (1,2,3,4,5,6,7,8,9,10), which is circular, meaning the number after the last one is again the first one (next(10)=1).

For a given number i>0 in the range, I would like to calculate the next m-th, and previous m-th number. e.g. next(5,1)=6 next(10,1)=1 next(10,2)=2 prev(5,2)=3 prev(1,1)=10 prev(1,2)=9.

For next I can just take (i+m)%n where n is the length of the range (n=10 in the example). But for prev I couldn't find an elegant solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

春庭雪 2024-10-02 09:20:50

您可以查看 Tie::Cycle 的源代码,这是我创建的一个用于循环的模块任意列表。

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

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

You might look at the source to Tie::Cycle, a module I created to cycle through arbitrary lists.

Remember that numbers are really just glyphs that stand in for something. If you have a Perl list of these glyphs, you still have a sequence starting at zero because you do the math on the list indices, not the glyphs. When you've selected the right list index, you use the element at that index.

If you want very large lists or lazy lists, you can still do this, but you just have to do a bit more work.

站稳脚跟 2024-10-02 09:20:50

我在 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

I have this solution in 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
灰色世界里的红玫瑰 2024-10-02 09:20:50

我发现下面的一行代码对于 JavaScript 和其他语言来说非常优雅,可以将 0 处理为逻辑错误:

const res = val % n || n;

用除数 (n) 对您的值 (val) 取模。当结果为 0 时,返回除数。

I found the following one-liner quite elegant for JavaScript and other languages, that can handle 0 as logically false:

const res = val % n || n;

Modulo your value (val) with your divisor (n). When this results in 0, return the divisor instead.

歌枕肩 2024-10-02 09:20:50

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

Say you want to map from 1 to n not 0 to n-1 eg n=5, range 1 to x, results 0 to 4,0mod5=0 1mod5=1, 2mod5=2... xmod5 results 0 whenever x=5*k. Use ((x-1)mod5)+1, x must be >0. This will always map (count) in 1 to 5 range, instead 0 to 4.

冰雪之触 2024-10-02 09:20:49

减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; }

Just subtract 1 and add 1 afterwards.

In most programming languages, you need to watch out when finding a "previous" value, because for negative numbers, modulo does not work as you want in this case: it returns a negative number.

Here's the C/C++ version:

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; }

However, in Perl modulo always returns a positive value (at least when the second operand is a positive integer). Basically it does what you want. So you can write the following and leave out the + $_[2]:

sub nxt { ($_[0] + $_[1] - 1) % $_[2] + 1; }
sub prv { ($_[0] - $_[1] - 1) % $_[2] + 1; }
绿光 2024-10-02 09:20:49

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

请尝试以下操作:

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

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

对于 prev,首先添加 n 以确保您永远不会对负数取模

Your next = (i + m) % n isn't right anyway - it'll return zero in some cases.

Try this instead:

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

In effect, take one off, then find the correct value, and then add the one back on again.

For prev, add n first to ensure that you never take the modulo of a negative number

好多鱼好多余 2024-10-02 09:20:49

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

What is difference between next(i,m) and previous(i,-m)? Nothing!. So let's go (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
抠脚大汉 2024-10-02 09:20:49

如果你不介意的话,先简单说几句。

您在实现“prev”函数时的困惑来自于在正整数和负整数域中思考这个问题。从几何角度考虑,如果您想象一个具有 10 个等距点的圆,那么解决方案如下所示:

正如您正确指定的那样,给定一个范围 [x..z],其中范围是圆形的,您可以找到下一个第 m 个数字为 (i+m)%k,其中 i 属于 [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

数字 5 的前 3 个 = prev(3,5) = (5+10-3)%10 = 12%10 = 2 。
诸如此类,等等。
非常简单、优雅,是吗?

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

希望这有帮助,
贾斯。

A few words in general first, if you don't mind.

Your confusion in implementing a "prev" function comes from thinking about this problem in domains of positive and negative integers. Think about it in terms of geometry, if you visualized a circle with 10 equally spaced points then solution looks like this :

As you correctly specified, given a range [x..z], where range is circular, you can find the next m-th number as (i+m)%k where i belongs to [x..z] and k is the length of the range.

Now, for the "previous" m-th member.
The previous number can be found by calculating (or more visually expressed, "arriving at") the previous m-th number position like this (pseudocode) :

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

For example, if you take the previous first of number 10 , then

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

Previous 3rd for number 5 = prev(3,5) = (5+10-3)%10 = 12%10 = 2 .
Etcetera, etcetera.
Very simple, and elegant, huh?

The only caveat here is that if i == m , the modulo will be a zero, so you need a handling mechanism for this result in both the next() and prev() functions.

Hope this helps,
Jas.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文