Есть ли способ реализовать эту очень простую логическую логику, используя только математические операнды (например, мод)? - PullRequest
6 голосов
/ 17 февраля 2010

Я хочу уменьшить значение на единицу, и, если оно достигнет нуля, установить максимальное значение. Есть ли способ сделать это с помощью математики, не прибегая к if (n-1 == 0) { n = max; }

Обратный сценарий увеличения значения на единицу и последующего обнуления, когда оно больше максимального, может быть легко достигнуто с помощью n = (n + 1) % (max + 1);. Кроме того, это даже лучше, так как вы можете увеличить на любую величину (не только на одну), и она все равно будет правильно «оборачиваться».

Спасибо за ответы. Чтобы было ясно, я имел в виду вообще без булевой логики (если / еще) или булевых операторов (!, && и т. Д.). Мне было просто любопытно, как это сделать. Действительно ли правильный ответ ниже действительно делает его более нечитаемым, пока предоставляется комментарий? Было бы необходимо использовать это для более общего случая вычитания произвольного числа и ожидания правильного переноса.

Ответы [ 11 ]

6 голосов
/ 17 февраля 2010
n = max - ((max - n +1)%max)
5 голосов
/ 17 февраля 2010

Если вы делаете это исключительно из соображений производительности, я бы посоветовал против этого. % обычно довольно дорогая операция на большинстве архитектур - простое сравнение, ветвление и сложение обычно будут более эффективными. Конечно, применяются обычные предостережения о спекулятивной / преждевременной оптимизации.

1 голос
/ 17 февраля 2010

Существует достаточно различий в математике между языками, и я сомневаюсь, что существует не зависящий от языка способ сделать это. Просто слишком много различий в том, как языки пишут выражения для базовой единой техники, чтобы работать с каждым возможным языком.

Если вы выберете определенный язык, вполне вероятно, что это возможно. Например, в C или C ++ вы можете сделать что-то вроде: n = (n-1) + ((n-1) == 0) * max;

В случае, если вас волнует, как это работает: в C сравнение (== в данном случае) дает результат 0 для false и 1 для true. Поэтому мы добавляем max * 0 когда / если n-1 != 0 и max * 1 когда / если n-1 == 0.

1 голос
/ 17 февраля 2010

Проблема в том, что оператор % в C возвращает отрицательный результат, когда сталкивается с отрицательным дивидендом. Это часто не то, что нужно.

Если вам нужна функция mod, которая будет выполнять -1 mod n == n-1, то в C вы должны сделать следующее:

int mod(int a, int b)
{
    return (a%b + b) % b;
}

Вы можете сделать

n=mod(n-1, max+1);

чтобы уменьшить n и сделать так, чтобы оно было max, когда n==0. Обратите внимание, что в случае приращения это будет работать для произвольных размеров шагов.

0 голосов
/ 18 февраля 2010

Просто чтобы спросить: почему вы хотите избежать логической операции?

Если вы хотите избежать условного кода в вашем приложении, вы можете использовать логические выражения, которые хранятся в логических значениях.Они будут сопоставлены с инструкциями SETcc на i386, и я предполагаю, что аналоговые инструкции существуют на других ISA.

В этом случае вы можете использовать логическое выражение и при этом иметь безусловный код, и вы можете использовать:

В предположении, что логический результат true равен Ordinal 1 (это имеет место в коде Delphi), а логическое значение false равно 0, вы можете написать

next := current - 1 + ( ( 1 + max ) and -Ord( current = 0 ) );

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

Тем не менее: я думаю, что условный код гораздо более читабелен.

0 голосов
/ 17 февраля 2010

Re: нет логических значений
Что ж, благодаря магии целочисленного деления (в стиле C) мой предыдущий ответ можно записать в виде:
n = ((max-n) / max) * max + ((max + n-1) / max) * n;

0 голосов
/ 17 февраля 2010

Как насчет этого:
n =! n * max + (!! n) * n;

0 голосов
/ 17 февраля 2010

На самом деле вы можете сделать также

n = (n - 1) + ((!(n - 1)) * max);
0 голосов
/ 17 февраля 2010

На любом языке оценки логики короткого замыкания (большинство современных языков) вы можете сделать что-то вроде этого:

--n<=0 && n=max;

У некоторых из ваших коллег вы можете получить волосатые глаза, если ваша команда не привыкла использовать && в качестве оператора if-then.

Чтобы сделать приращение прямого цикла:

++n>max && n=1;

Эти примеры предполагают счетчик с 1 индексом, поскольку ваш вопрос, похоже, предполагает это. 0-индексированные эквиваленты:

--n<0 && n=max-1;

++n>=max && n=0;

0 голосов
/ 17 февраля 2010

Возможно, есть лучший способ, но я думаю n = max - (max - n + 1) % (max + 1) работает. Я предполагаю, что вы хотите включить 0 на обоих концах, так как для выражения приращения вы включаете 0.

...