一个按位表达式,当掩码全为零时返回1,当掩码全为一时返回x。

huangapple go评论70阅读模式
英文:

a bitwise expression that returns 1 when mask is all zeros and x when mask is all ones

问题

让我们假设我们有一个名为 mask 的变量,它可以是 0(全零)或 -1(全一)。

我有另一个变量 x,假设它是 42

可能的位运算表达式是什么,可以实现以下结果:

  • mask == 0 时,结果为 1
  • mask == -1 时,结果为 x

我试图探索消除以下 if 语句的方法:

unsigned x = 3;
unsigned some_number = 42;

// ~~~

if (some_number % x == 0)
{
    some_number /= x;
}

关于我正在解决的特定问题中的变量类型(请看下文),所有数字都是无符号整数,例如 unsigned


编辑 2(错误):我犯了个错误,忘记了 mask 可以是 0全零)或 -1全一),而我之前说过是 1(只有最低有效位为一)。请接受我的道歉,因为我浪费了您宝贵的时间


编辑 1

总的来说,重点不是使用 if-else 结构(包括条件运算符(?:))。我正在寻找类似于在无分支实践中使用的位操作方式。这个问题不是关于在这种情况下是否更高效,或者答案是否可以被视为良好实践的问题。只是为了探索位操作的世界。


以下是我的尝试:

// 检查 some_number 是否能被 x 整除
unsigned mask = ((some_number % x) - 1) >> 31;
unsigned denom = // ??
some_number /= denom;

我正在使用这个来回答项目欧拉的第三个问题,这里是代码:

size_t largest_prime_factor(size_t number)
{
    if (number < 2) return 0;
    if (number == 2) return 2;
    while ((number & 1) == 0)
    {
        number >>= 1;
    }
    size_t lpf = 2;
    size_t i = 3;
    size_t max_iter = sqrt(number);
    while (i < max_iter)
    {
        size_t mask = ((number % i) - 1) >> 31;
        lpf = (i & mask) | (lpf & ~mask);
        number /= x; // mask = 0 => x=1; mask = 1 => x=i
        i += 2;
    }
    return lpf;
}

注意:如果可能的话,请建议一个更好的标题。

英文:

Let's say we have a mask variable that can either be 0 (all zoers) or -1 (all ones).

I have another variable x which is let's say 42.

What (possibly) is the bitwise expression that results in:

  • 1 when mask == 0
  • x when mask == -1

what I'm trying to do is explore ways to eliminate the following if statement

unsigned x = 3;
unsigned some_number = 42;

// ~~~

if (some_number % x == 0)
{
    some_number /= x;
}

Regarding the type of variables in the particular problem that I'm working on (look below), all of the numbers are unsigned integers for example unsigned.


EDIT 2 (MISTAKE): I made a mistake and forgot that mask is either 0 (all zeros) or, -1 (all ones) which I previously said 1 (only whose least significant bit is one). Please accept my apologies as I wasted your precious time.


EDIT 1:

Overall the point is not to use if-else constructs (including the conditional operator (?:)). Instead I'm looking for bit manipulations similar to those which is used in branchless practices. This question isn't whether it is going to be more performant or not in this case, or whether the answer could be considered a good practice or not. It's just to explore the world of bit manipulation.


Here is my try

// Check whether some_number is divisible by x
unsigned mask = ((some_number % x) - 1) &gt;&gt; 31;
unsigned deonm = // ??
some_number =/ denom

I'm using this to answer project Euler's third question and here's the code

size_t largest_prime_factor(size_t number)
{
    if (number &lt; 2) return 0;
    if (number == 2) return 2;
    while ((number &amp; 1) == 0)
    {
        number &gt;&gt;= 1;
    }
    size_t lpf = 2;
    size_t i = 3;
    size_t max_iter = sqrt(number);
    while (i &lt; max_iter)
    {
        size_t mask = ((number % i) - 1) &gt;&gt; 31;
        lpf = (i &amp; mask) | (lpf &amp; ~mask);
        number /= X; // mask = 0 =&gt; X=1; mask = 1 =&gt; X=i
        i += 2;
    }
    return lpf;
}

NOTE: Please, if possible, suggest a better title.

答案1

得分: 3

在您的特定情况下,您可能希望避免分支:除法可能很昂贵,而正确预测的分支可能很便宜。如果分支不经常执行(例如,暴力因数分解),则结果将比始终除以计算出的除数要快。

如果您只想要一个无分支的解决方案:

(x - 1) * mask + 1

可以工作,但由于乘法操作,不一定会更快。或者,如果mask是无符号的,您可以使用((x - 1) & -mask) + 1,这可能稍微更快。

您还可以稍微并行化这个过程以减少依赖链:(x & -mask) + !mask

英文:

In your particular case, you may not want to avoid the branch: divisions can be expensive, while a correctly predicted branch can be cheap. If the branch is not taken frequently (e.g. brute-force factoring), the result will be faster than trying to always divide by a computed divisor.

If you just want a branchless solution:

(x - 1) * mask + 1

works, but won't necessarily be faster due to the multiply. Alternatively, if mask is unsigned, you could use ((x - 1) &amp; -mask) + 1 which is probably slightly faster.

You can also parallelize this a bit to reduce the dependency chain: (x &amp; -mask) + !mask.

答案2

得分: 2

对于 `mask` 可以是 `0`  `1` 的情况
```c
1 - mask  // 或 !mask => 当 mask 为 0 时为 1
+         
x * mask  //          => 当 mask 为 1 时为 x
英文:

For the case where mask can be either 0 or 1

1 - mask  // or !mask =&gt; 1 when mask is 0
+         // or |
x * mask  //          =&gt; x when mask is 1

答案3

得分: 1

我会假设掩码(我将其称为m)、x和结果(我将其称为r)都是相同大小的无符号整数类型。我将称此类型为TYPE

对于大多数位来说,很容易:ri = xi & mi

然而,最不显著的位(r0)不同。以下显示了根据m0和x0的值所需的r0的值:

r0 m0 = 0 m0 = 1
x0 = 0 1 0
x0 = 1 1 1

因此,我们得到 r0 = ~m0 | x0

现在,我们只需要将它们组合起来。

我们想要将第一个规则应用于除了最后一位之外的所有位。这可以通过使用一个允许除了最后一位之外的所有位通过的掩码来完成(... & ( ~(TYPE)1 ))。

我们想要仅针对最后一位应用第二个规则。这可以通过使用一个仅允许最后一位通过的掩码来完成(... & 1)。

全部放在一起:

r = ( x & m & ( ~(TYPE)1 ) ) | ( ( ~m | x ) & 1 );

现在我们有一个只使用位操作的解决方案(和一个可能可以通过使用正确的数字文字后缀来避免的强制转换)。

英文:

I'm going to assume the mask (which I'll call m), x, and the result (which I'll call r) are unsigned integer types of the same size. I shall call that type TYPE.


For most of the bits, it's easy: r<sub>i</sub> = x<sub>i</sub> & m<sub>i</sub>

The least significant bit (r<sub>0</sub>) is different, though. The following shows the desired value for r<sub>0</sub> based on the values of m<sub>0</sub> and x<sub>0</sub>:

r<sub>0</sub> m<sub>0</sub> = 0 m<sub>0</sub> = 1
x<sub>0</sub> = 0 1 0
x<sub>0</sub> = 1 1 1

So we get r<sub>0</sub> = ~m<sub>0</sub> | x<sub>0</sub>

Now, we just need to combine them.

We want to apply the first rule to all the bits but the last. This can be done by using a mask that lets through all bits but the last (... &amp; ( ~(TYPE)1 )).

We want to apply the second rule for just the last bit. This can be done by using a mask that lets through only the last bit (... &amp; 1).

All together:

r = ( x &amp; m &amp; ( ~(TYPE)1 ) ) | ( ( ~m | x ) &amp; 1 );

And now we have a solution with just bit operations (and a cast which can maybe be avoided by using the correct numeric literal suffix).

答案4

得分: 1

((x ^ 1) & mask) ^ 1

英文:

With xor, you can get a shorter solution:

 ((x ^ 1) &amp; mask) ^ 1

答案5

得分: 0

一个位与操作几乎可以产生所需的输出:

  • 如果您的无符号掩码全为1 -1U,则 mask & x == x
  • 如果您的无符号掩码全为零 0U,则 mask & x == 0

我们可以通过另一个操作来补充看到:

  • 如果您的无符号掩码全为1 -1U,则 mask + 1 == 0
  • 如果您的无符号掩码全为零 0U,则 mask + 1 == 1

通过总结这两个表达式 mask + 1 + (mask & x),您可以获得您想要的结果:

  • mask == 0U 时,得到 1
  • mask == -1U 时,得到 x
英文:

A bit and operation does almost produce the desired output:

  • if your unsigned mask is all ones -1U then mask &amp; x == x
  • if your unsigned mask is all zeros 0U then mask &amp; x == 0

We see that we can complement with another operation:

  • if your unsigned mask is all ones -1U then mask + 1 == 0
  • if your unsigned mask is all zeros 0U then mask + 1 == 1

By summing up the two expressions mask + 1 + (mask &amp; x) you get what you want:

  • 1 when mask == 0U
  • xwhen mask == -1U

huangapple
  • 本文由 发表于 2023年7月18日 02:15:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76707116.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定