Если вы знаете размер целочисленного типа, вы можете извлечь его знаковый бит (при условии дополнения до двух), используя целочисленное деление:
// Example in C
int sign_bit(int s)
{
// cast to unsigned (important)
unsigned u = (unsigned)s;
// number of bits in int
// if your integer size is fixed, this is just a constant
static const unsigned b = sizeof(int) * 8;
// pow(2, b - 1)
// again, a constant which can be pre-computed
static const unsigned p = 1 << (b - 1);
// use integer division to get top bit
return (int)(u / p);
}
Возвращает 1, если s < 0
, и 0 в противном случае; его можно использовать для вычисления абсолютного значения :
int abs_arith(int v)
{
// sign bit
int b = sign_bit(v);
// actual sign (+1 / -1)
int s = 1 - 2 * b;
// sign(v) * v = abs(v)
return s * v;
}
Желаемая функция выглядит так:
Полезно сначала сдвинуть минимум к нулю:
Эта функциональная форма может быть вычислена как сумма двух сдвинутых абсолютных значений функций ниже:
Однако результирующая функция масштабируется с коэффициентом 2; здесь помогает смещение на ноль, потому что нам нужно только разделить на 2 и вернуться к исходному минимуму:
// Example in C
int clamp_minmax(int val, int min, int max)
{
// range length
int range = max - min;
// shift minimum to zero
val = val - min;
// blue function
int blue = abs_arith(val);
// green function
int green = range - abs_arith(val - range);
// add and divide by 2
val = (blue + green) / 2;
// shift to original minimum
return val + min;
}
Это решение, хотя и удовлетворяет требованиям проблемы, ограничено целочисленными типами со знаком (и языками, которые допускают целочисленное переполнение - я не уверен, как это можно преодолеть, например, в Java).