Как я могу по модулю, когда мои числа начинаются с 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