Я думал, как получить абсолютное значение целого числа без использования оператора if
или abs()
. Сначала я использовал сдвиговые бит слева (<<
), пытаясь получить отрицательный знак из диапазона, а затем сдвигайте биты прямо туда, где он есть, но, к сожалению, это не работает для меня. Пожалуйста, дайте мне знать, почему это не работает и другие альтернативные способы сделать это.
Получить абсолютное значение без использования функции abs, а также выражение
Ответ 1
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);}