仅使用算术限制最小值和最大值之间的值
Limit a value between min and max using only arithmetic
是否可以仅使用算术将值限制在最小值和最大值之间的给定范围内?即 +
-
x
/
和 %
?
我无法使用 min
、max
或 IF
语句等功能。
假设我的范围是 [1850, 1880]
,对于任何值 < 1850
,它应该显示 1850
。对于值 > 1880
,应显示 1880
。如果只在范围外显示1850
也是可以接受的。
我试过了:
x = (((x - xmax) % (xmax - xmin)) + (xmax - xmin)) % (xmax - xmin) + xmin
但对于低于 xmin
.
的值,它会在范围中间给出不同的值
如果知道整数类型的大小,则可以使用整数除法提取其符号位(假设为二进制补码):
// 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);
}
此 returns 如果 s < 0
为 1,否则为 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 中克服这一点)。
我在闲逛时发现了这个……excel。它仅适用于严格的正整数。尽管这并不像 meowgoesthedog 的答案那样具有更多限制性,因为他还通过在最后除以 2 有效地将整数 space 减半。它不使用 mod.
//A = 1 if x <= min
//A = 0 if x >= min
A = 1-(min-min/x)/min
//B = 0 if x <= max
//B = 1 if x > max
B = (max-max/x)/max
x = A*min + (1-A)*(1-B)*x + B*max
我在 Python 中找到了这个解决方案:
A = -1 # Minimum value
B = +1 # Maximum value
x = min(max(x, A), B)
是否可以仅使用算术将值限制在最小值和最大值之间的给定范围内?即 +
-
x
/
和 %
?
我无法使用 min
、max
或 IF
语句等功能。
假设我的范围是 [1850, 1880]
,对于任何值 < 1850
,它应该显示 1850
。对于值 > 1880
,应显示 1880
。如果只在范围外显示1850
也是可以接受的。
我试过了:
x = (((x - xmax) % (xmax - xmin)) + (xmax - xmin)) % (xmax - xmin) + xmin
但对于低于 xmin
.
如果知道整数类型的大小,则可以使用整数除法提取其符号位(假设为二进制补码):
// 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);
}
此 returns 如果 s < 0
为 1,否则为 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 中克服这一点)。
我在闲逛时发现了这个……excel。它仅适用于严格的正整数。尽管这并不像 meowgoesthedog 的答案那样具有更多限制性,因为他还通过在最后除以 2 有效地将整数 space 减半。它不使用 mod.
//A = 1 if x <= min
//A = 0 if x >= min
A = 1-(min-min/x)/min
//B = 0 if x <= max
//B = 1 if x > max
B = (max-max/x)/max
x = A*min + (1-A)*(1-B)*x + B*max
我在 Python 中找到了这个解决方案:
A = -1 # Minimum value
B = +1 # Maximum value
x = min(max(x, A), B)