Для данного числа установите переменную -1, если она отрицательна, и 1, если она положительна (без использования if). - PullRequest
3 голосов
/ 05 июля 2010

Мне часто нужны такие функции, например, чтобы понять направление касаний на iPhone, и единственный способ решить эту проблему - использовать логику, например:

int dir,distY;
distY = newY-oldY;

if (distY > 0) 
{
    dir = 1;
}
else if (distY < 0) 
{
    dir = -1;
}

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

Уточнение, похожий пример того, что я ищу:

i = ++i % max;

вместо:

i++;
if ( i > max ) { i = 0; }

Ответы [ 8 ]

2 голосов
/ 05 июля 2010

Если вы используете что-то вроде C или C ++, которое преобразует true в 1 и false в 0, вы можете использовать: direction = (distY > 0) - (distY < 0);.Вы не сказали, что хотели, когда distY=0 - это дает 0 (что кажется мне очевидным выбором, но кто знает).

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

2 голосов
/ 05 июля 2010

Если вы знаете, что значение будет отличным от нуля, вы можете просто разделить его на абсолютное значение:

dir = distY / abs(distY);

Если оно может быть нулевым, и вы все равно хотите установить флаг на что-то, вы можетесделать что-то вроде этого (в C / C ++):

dir = distY >= 0 ? 1 : -1;

Это установит dir в 1, когда distY также равен нулю.

1 голос
/ 05 июля 2010

Кажется, вы ищете функцию signum.Если у вашего языка / библиотек программирования его нет, его довольно легко написать: просто оберните операторы if / else в функцию, чтобы ее было проще и приятнее использовать.

С математическими обозначениями:

sign(n) =  
|-1 if n < 0  
| 0 if n = 0  
| 1 if n > 0

Если он медленнее или быстрее, то манипулирование битами зависит от языка, целевой платформы и библиотеки (если вы ее используете).Вовлечение abs любым способом (как рекомендуется в некоторых ответах), вероятно, является излишним, так как оно будет содержать почти ту же логику, и у вас есть еще один вызов и деление + вам придется иметь дело с потенциальным делением на ноль.

1 голос
/ 05 июля 2010

direction = distY / abs (distY)

Вам все равно нужно будет проверить, что distY не равно 0.

0 голосов
/ 03 июля 2012

На любом языке, который поддерживает базовые битовые операции (сдвиги), это работает - даже если язык явно не использует 0 и 1 для FALSE и TRUE.

C # образец:

    // Explanatory version:
    static int Sign(int val)
    {
        val = -(int)((uint)val >> 31); // int is 32 bit, so shift by n - 1.
        // uval now contains -1 for negative and 0 for positive.
        return val * 2 + 1;
        // -1 * 2 + 1 = -1
        //  0 * 2 + 1 = +1
    }

    // Terse form:
    static int Sign(int val)
    {
        return 1 - (int)((uint)val >> 31) * 2;
    }

Это из-за того, что отрицательные числа представлены на младшем порядке дополнения до двух (например, x86 / x64). В основном, первый бит в числе будет равен «1» для отрицательных значений (см. Статью для примера).

  1. Сначала мы приведем его к неподписанному формату. Это исключает какую-либо особую обработку языка для операций переноса в подписанных форматах (например, .Net).
  2. На этом этапе мы могли бы и сделать AND операцию с ним и 0x80000000. Это исключило бы биты, не связанные со знаком, из значения. Нам не нужно делать это из-за того, как работает сдвиг (если ваш язык имеет только ROL и ROR, вам сначала нужно будет сделать это И).
  3. Смещаем значение вправо на 31 бит. Оператор сдвига «уничтожит» любые биты, которые «падают» с конца, поэтому у нас остается либо 1, либо 0 в бите 2^0. Это означает, что если значение отрицательное, оно будет равно 1, а если оно положительное, то будет 0.
  4. Мы приводим его обратно к int и затем используем простую математику для отображения 0 и 1 в 1 и -1 соответственно.

Если вы нацелены на big-endian, я думаю, что просто изменение смены должно дать правильный результат.

0 голосов
/ 05 июля 2010

Вы, вероятно, могли бы сказать мне, если есть что-то подобное в C, но в Perl есть только оператор равенства для задания.

Оператор <=> будет использоваться следующим образом:

$dir = $distY <=> 0;

Из документации (perldoc perlop):

Binary "<=>" возвращает -1, 0 или 1 в зависимости от того, числовой аргумент левого аргументаменьше, равно или больше, чем правильный аргумент.

Теперь я хотел бы знать, существует ли нечто подобное в C, C ++ и / или Objective-C.

0 голосов
/ 05 июля 2010

Если вы используете язык, где 0 - ложь, а 1 - истина (или предлагает преобразование типа), то в псевдокоде:

i = abs(distY) == distY; // 0 or 1
i = i*2 - 1; // -1 or 1
0 голосов
/ 05 июля 2010

Если вы настаиваете на краткости, попробуйте

(i>0)?1:((i<0)?-1:0)

(при условии, что вы хотите охватить нулевой случай наиболее разумным способом).

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

Лично я бы использовал конструкцию if-else.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...