问题
像 xor-swap algorithm 这样的技巧给我留下了深刻的印象和类似的。所以我问自己,是否可以为变量分配一个值,但前提是该值为正数 - 不使用任何类型的 if
或隐藏条件;只是纯数学。
替代方案
基本上,这但没有 if
:
int a = ...
int b = ...
if (b >= 0) {
a = b;
}
示例
以下是一些示例输入/输出设置,用于说明所需的逻辑:
a = 1, b = 10 -> a = 10 // b is positive
a = 1, b = 0 -> a = 0 // b is 0, also positive
a = 1, b = -10 -> a = 1 // b is negative
最佳答案
tl;博士
int a = ...
int b = ...
int isNegative = b >>> 31; // 1 if negative, 0 if positive
int isPositive = 1 - isNegative; // 0 if negative, 1 if positive
a = isPositive * b + isNegative * a;
签名
完成该任务的一个简单方法是尝试获取某种signum ,或者更具体地说是一种获得因子
的方法- 要么
0
,如果b
为正 - 如果
b
为负,则为1
,反之亦然。
现在,如果您看一下 int
在内部如何用 32 位表示(这称为 Two's complement ):
// 1234
00000000 00000000 00000100 11010010
// -1234
11111111 11111111 11111011 00101110
您会看到它的最左侧有所谓的符号位,即 most-significant-bit 。事实证明,您可以通过简单的位移轻松提取该位,只需将整个位模式向右移动 31
次,只留下第 32
位,即符号位:
int isNegative = b >>> 31; // 1 if negative, 0 if positive
现在,要获得相反的方向,只需对其取反并在其顶部添加 1
即可:
int isPositive = 1 - isNegative; // 0 if negative, 1 if positive
Annihilator和 Identity
一旦掌握了这一点,您就可以通过利用以下事实轻松构建您想要的值
- 与
0
相乘基本上会删除参数(0
是*
的 annihilator) - 与
0
相加不会改变该值(0
是+
的 identity 元素)。
那么,回到我们首先想要实现的逻辑:
- 如果
b
为正,我们需要b
- 如果
b
为负,我们需要a
因此,我们只需执行 b * isPositive
和 a * isNegative
并将它们相加即可:
a = isPositive * b + isNegative * a;
现在,如果 b
为正,您将得到:
a = 1 * b + 0 * a
= b + 0
= b
如果是负数,你会得到:
a = 0 * b + 1 * a
= 0 + a
= a
其他数据类型
同样的方法也可以应用于任何其他带符号的数据类型,例如byte
、short
、long
、float
和 double
。
例如,以下是 double
的版本:
double a = ...
double b = ...
long isNegative = Double.doubleToLongBits(b) >>> 63;
long isPositive = 1 - isNegative;
a = isPositive * b + isNegative * a;
不幸的是,在Java中你不能直接在double
上使用>>>
(因为弄乱指数和尾数通常也没有意义),但因此你有 helper Double#doubleToLongBits
它基本上将 double
重新解释为 long
。
关于java - 赋值,但仅限于正数 - 无条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69227706/