Как я могу по модулю, когда мои числа начинаются с 1, а не с нуля?

Я думаю, что решение для этого довольно простое, но я некоторое время думал об этом и не мог придумать элегантное решение.

У меня есть ряд чисел, например. 1..10 = (1,2,3,4,5,6,7,8,9,10), который является круглым, то есть число после последнего снова является первым (next(10)=1).

Для данного номера i>0 в диапазоне, я хотел бы рассчитать следующее m -th и предыдущее 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

Просто вычтите 1 и добавьте 1 после.

В большинстве языков программирования вам нужно следить за поиском "предыдущего" значения, потому что для отрицательных чисел модуль не работает так, как вы хотите в этом случае: он возвращает отрицательное число.

Здесь версия 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 modulo всегда возвращается положительное значение (по крайней мере, когда второй операнд является положительным целым числом). В основном он делает то, что вы хотите. Поэтому вы можете написать следующее и оставить + $_[2]:

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

Ответ 2

Ваш next = (i + m) % n не прав в любом случае - в некоторых случаях он будет возвращать ноль.

Попробуйте это вместо:

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

По сути, отведите один, затем найдите правильное значение, а затем снова добавьте его.

Для prev сначала добавьте n, чтобы убедиться, что вы никогда не принимаете по модулю отрицательное число

Ответ 3

В чем разница между 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

Ответ 4

Несколько слов вообще, если вы не возражаете.

Ваше замешательство в реализации функции "prev" происходит от мысли об этой проблеме в областях положительных и отрицательных целых чисел. Подумайте об этом с точки зрения геометрии, если вы визуализировали круг с 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

Предыдущий третий для числа 5 = prev(3,5) = (5+10-3)%10 = 12%10 = 2. Etcetera и т.д. Очень простой и элегантный, да?

Единственное предостережение здесь в том, что if i == m, modulo будет равен нулю, поэтому для этого результата нужен механизм обработки для следующих функций() и prev().

Надеюсь, это поможет, Иак.

Ответ 5

Вы можете посмотреть на источник Tie:: Cycle - модуль, который я создал для циклического перемещения по произвольным спискам.

Помните, что числа - это просто глифы, которые стоят за чем-то. Если у вас есть список Perl этих глифов, у вас все еще есть последовательность, начинающаяся с нуля, потому что вы делаете математику в индексах списка, а не в глифах. Когда вы выбрали индекс правого списка, вы используете элемент в этом индексе.

Если вам нужны очень большие списки или ленивые списки, вы все равно можете это сделать, но вам просто нужно немного поработать.

Ответ 6

У меня есть это решение в R:

pred <- function(n) n - 1L # cf. Pascal pred
succ <- function(n) n + 1L # cf. Pascal 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