Подтвердить что ты не робот

Получить абсолютное значение без использования функции abs, а также выражение

Я думал, как получить абсолютное значение целого числа без использования оператора if или abs(). Сначала я использовал сдвиговые бит слева (<<), пытаясь получить отрицательный знак из диапазона, а затем сдвигайте биты прямо туда, где он есть, но, к сожалению, это не работает для меня. Пожалуйста, дайте мне знать, почему это не работает и другие альтернативные способы сделать это.

4b9b3361

Ответ 1

От Бит Tweedling Hacks:

int v;           // we want to find the absolute value of v
unsigned int r;  // the result goes here 
int const mask = v >> sizeof(int) * CHAR_BIT - 1;

r = (v + mask) ^ mask;

Ответ 2

int abs(int v) 
{
  return v * ( (v<0) * (-1) + (v>0));
  // simpler: v * ((v>0) - (v<0))   thanks Jens
}

Этот код умножает значение v на -1 или 1, чтобы получить abs (v). Следовательно, внутри скобки будет один из -1 или 1.

Если v положительно, выражение (v>0) истинно и будет иметь значение 1, а (v<0) - false (со значением 0 для false). Следовательно, когда v положительно ((v>0) - (v<0)) = (1-0) = 1. И все выражение: v * (1) == v.

Если v отрицательно, выражение (v>0) является ложным и будет иметь значение 0, а (v<0) - true (значение 1). Таким образом, для отрицательных v, ((v>0) - (v<0)) = (0-1) = -1. И все выражение: v * (-1) == -v.

Когда v == 0, обе (v<0) и (v>0) будут вычисляться до 0, оставляя: v * 0 == 0.

Ответ 3

Внеофисный *

int abs (int n) {
    const int ret[2] = { n, -n };
    return ret [n<0];
}

Примечание 4.7 Интегральные преобразования /4: [...] If the source type is bool, the value false is converted to zero and the value true is converted to one.


<суб > *: в том смысле, что в вашем коде нет условного разветвления. Под капотом тройной оператор также создает ветку. Тем не менее, это также действительный ответ, потому что тройной не является if-утверждением. Это не означает, что ваш компилятор не может испускать код сборки без ветвей для кода, который логически разделяет.

Ответ 4

Предполагая 32-разрядные целые числа со знаком (Java), вы можете написать:

public static int abs(int x)
{
    return (x + (x >> 31)) ^ (x >> 31);
}

Нет умножения, нет ветки.

BTW, return (x ^ (x >> 31)) - (x >> 31); будет работать, но он запатентован. Да!

Примечание. Этот код может занять более 10 раз больше условного оператора (8 бит Verison). Это может быть полезно для аппаратного программирования System C и т.д.

Ответ 5

Битовые сдвиги целых чисел со знаком, как вы считаете, - это поведение undefined и, следовательно, не вариант. Вместо этого вы можете сделать это:

int abs(int n) { return n > 0 ? n : -n; }

Нет if, только условное выражение.

Ответ 6

Я пробую этот код в C, и он работает.

int abs(int n){
   return n*((2*n+1)%2); 
}

Надеюсь, что этот ответ будет полезен.

Ответ 7

Попробуйте следующее:

int abs(int n) 
{
  return sqrt(n*n);
}

Ответ 8

Вот еще один подход без abs(), если и никакого логического/условного выражения: Предположим, что int представляет собой 32-битное целое число. Идея довольно проста: (1 - 2 * sign_bit) преобразует sign_bit = 1 / 0 to -1 / 1.

unsigned int abs_by_pure_math( int a ) {
   return (1 - (((a >> 31) & 0x1) << 1)) * a;
}

Ответ 9

Не видел этого. Для двух дополнительных представлений и 32 бит int

( n >> 31 | 1 ) * n

Ответ 10

Если ваш язык позволяет использовать bool для int cast (например, C/C++):

float absB(float n) {
    return n - n * 2.0f * ( n < 0.0f );
}

Ответ 11

Используйте тернарный оператор:

y = condition ? value_if_true : value_if_false;

Ответ 12

как насчет этого:

value = value > 0 ? value: ~value + 1

его основано на том факте, что отрицательные числа сохраняются как 2 дополнения к положительному эквиваленту, и что можно построить 2 дополнения, сначала построив 1 дополнение и добавив 1, поэтому

 5 ->   0000 0101b
-5 ->  (1111 1010b) + 1 -> 1111 1011b 

то, что я сделал, в основном, чтобы отменить это, поэтому

-5 ->  1111 1011b
 5 -> (0000 0100b) + 1 -> 0000 0101b

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

Ответ 13

Нет веток или умножения:

int abs(int n) {
    int mask = n >> 31;
    return (mask & -n) | (~mask & n);
}

Ответ 14

Есть несколько причин, из-за которых сдвиг знака и смещение вправо (v << 1 >> 1):

  • смещение влево знака с отрицательным значением имеет поведение undefined, поэтому его вообще не следует использовать.
  • значение unsigned будет иметь желаемый эффект: (unsigned)v << 1 >> 1 избавляется от знакового бита, если нет битов заполнения, но результирующее значение является абсолютным значением v только для систем с знак + представление величины, которые в настоящее время исчезающе редки. В вездесущей архитектуре с двумя дополнениями результирующее значение для отрицательного v равно INT_MAX+1-v

Решение Hasturkun, к сожалению, имеет определенное поведение при реализации.

Вот вариация, которая полностью определена для систем с 2 дополнительными представлениями для подписанных значений:

int v;           // we want to find the absolute value of v
unsigned int r;  // the result goes here 
unsigned int mask = -((unsigned int)v >> (sizeof(unsigned int) * CHAR_BIT - 1));

r = ((unsigned int)v + mask) ^ mask;

Ответ 15

Что насчет этого:

#include <climits>

long abs (int n) { // we use long to avoid issues with INT MIN value as there is no positive equivalents.
    const long ret[2] = {n, -n};
    return ret[n >> (sizeof(int) * CHAR_BIT - 1)];    // we use the most significant bit to get the right index.
}

Ответ 16

Вы должны комбинировать побитовое и добавление.

Ответ 17

Что не так:

-1 * n

Использование минус минус равно плюс принцип

Ответ 18

Если вы хотите чисто математический способ, который не слишком дорогостоящий, попробуйте

f(x) = (x*x)/x

или в С++

function abs(auto x) {return ((x*x)/x);}