显然无需循环即可找到 32 位数字的最高位组索引
这是一个困难的问题(至少我很难过:P):
在不使用任何循环的情况下找到 32 位数字的最高位集的索引。
Here's a tough one(atleast i had a hard time :P):
find the index of the highest bit set of a 32-bit number without using any loops.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
基准解决方案的答案,
非常有趣的问题,我将为您提供使用循环的
这有助于更好地理解问题,但效率非常低。
使用日志的解决方案
这种方法也可以通过日志方法进行总结
,但是它的效率也很低(甚至比上面的方法还要低,请参阅基准测试)
使用内置指令的解决方案
这种解决方案虽然非常高效,但其缺点是它只适用于特定的编译器(gcc 和 clang 都可以)和特定的平台上。
注意:如果我们想要索引,则为 31 而不是 32
具有内在的解决方案
这将在汇编级别调用 bsr 指令
使用内联汇编的解决方案
LZCNT 和 BSR 可以用以下函数在汇编中进行总结:
NB :除非您知道自己在做什么,否则不要使用
使用查找表和幻数乘法的解决方案(可能是最好的据我所知)
首先,您使用以下函数来清除除最高位之外的所有位:
信用:这个想法来自Henry S. Warren, Jr. 在他的书 Hacker's Delight
然后我们使用基于 DeBruijn 序列的算法 执行一种二分搜索:
另一个版本:
基准测试,调用次数为 1 亿次
使用
g++ -std=c++17 HighestSetBit.cpp 进行编译的 -O3 && ./a.out
如果您关注的是可移植性,我个人会选择 HighBitIndex8,否则内置的 gcc 就很好了。
Very interesting question, I will provide you an answer with benchmark
Solution using a loop
This help to better understand the question but is highly inefficient.
Solution using log
This approach can also be summarize by the log method
However it is also inefficient (even more than above one, see benchmark)
Solution using built-in instruction
This solution, while very efficient, suffer from the fact that it only work with specific compilers (gcc and clang will do) and on specific platforms.
NB: It is 31 and not 32 if we want the index
Solution with intrinsic
This will call the bsr instruction at assembly level
Solution using inline assembly
LZCNT and BSR can be summarize in assembly with the below functions:
NB: Do Not Use unless you know what you are doing
Solution using lookup table and magic number multiplication (probably the best AFAIK)
First you use the following function to clear all the bits except the highest one:
Credit: The idea come from Henry S. Warren, Jr. in his book Hacker's Delight
Then we use an algorithm based on DeBruijn's Sequence to perform a kind of binary search:
Another version:
Benchmark with 100 million calls
compiling with
g++ -std=c++17 highestSetBit.cpp -O3 && ./a.out
I would personally go for highestBitIndex8 if portability is your focus, else gcc built-in is nice.
使用递归:
[31,..,0]
索引| 1
通过限制移位次数直到达到1
来防止堆栈溢出 (32)With recursion:
[31,..,0]
indexing| 1
prevents stack overflow by capping the number of shifts until a1
is reached (32)以二为底的对数下限应该可以解决问题(尽管你必须特殊情况 0)。
顺便说一句,这实际上是一个非常糟糕的面试问题(我是作为一个为潜在候选人进行技术面试的人说的),因为它确实与您在实际编程中所做的任何事情都不相符。
您的老板不会有一天对您说:“嘿,所以我们对这项最新功能有一项紧急工作,并且需要在没有循环的情况下实现!”
Floor of logarithm-base-two should do the trick (though you have to special-case 0).
On an unrelated note, this is actually a pretty terrible interview question (I say this as someone who does technical interviews for potential candidates), because it really doesn't correspond to anything you do in practical programming.
Your boss isn't going to come up to you one day and say "hey, so we have a rush job for this latest feature, and it needs to be implemented without loops!"
你可以这样做(未优化):
You could do it like this (not optimised):
抱歉打扰了旧线程,但是这个怎么样
sorry for bumping an old thread, but how about this
这可以通过二分搜索来完成,将 O(N)(对于 N 位字)的复杂度降低到 O(log(N))。一种可能的实现是:
输入是32位无符号整数。
它有一个循环,可以转换为 5 级 if 语句,因此会产生 32 个左右的 if 语句。你也可以使用递归来摆脱循环,或者绝对邪恶的“goto”;)
this can be done as a binary search, reducing complexity of O(N) (for an N-bit word) to O(log(N)). A possible implementation is:
the input is a 32 bit unsigned integer.
it has a loop that can be converted into 5 levels of if-statements , therefore resulting in 32 or so if-statements. you could also use recursion to get rid of the loop, or the absolutely evil "goto" ;)
让
n - 要识别位位置的十进制数
start - 表示十进制值 ( 1 << 32 ) - 2147483648
bitLocation - 指示设置为 1 的位位置
Let
n - Decimal number for which bit location to be identified
start - Indicates decimal value of ( 1 << 32 ) - 2147483648
bitLocation - Indicates bit location which is set to 1
从主调用函数
high_bit_set(int n , int pos)
中输入值n
,默认31
作为最高位置。功能就像上面一样。From your main call function
high_bit_set(int n , int pos)
with the input valuen
, and default31
as the highest position. And the function is like above.Paislee 的解决方案 实际上很容易进行尾递归,不过,它比建议的 Floor(log2(n)); 慢得多。
此功能也适用于其他位大小,只需更改检查即可,
例如
Paislee's solution is actually pretty easy to make tail-recursive, though, it's a much slower solution than the suggested floor(log2(n));
This function also works for other bit sizes, just change the check,
e.g.
请注意,您想要做的是计算整数的整数 log2,
请注意,您可以尝试一次搜索超过 1 位。
这种方法使用了二分搜索
另一种二分搜索方法,也许更具可读性,
并且因为您将想要测试这些,
Note that what you are trying to do is calculate the integer log2 of an integer,
Observe that you can attempt to search more than 1 bit at a time.
This approach uses a binary search
Another binary search method, perhaps more readable,
And because you will want to test these,
据我所知,Log 函数在大多数编程语言中都非常有效地实现,即使它确实包含循环,内部也可能很少
所以我想说在大多数情况下使用日志会更快、更直接。
但你必须检查 0 并避免取 0 的日志,因为这会导致程序崩溃。
well from what I know the function Log is Implemented very efficiently in most programming languages, and even if it does contain loops , it is probably very few of them , internally
So I would say that in most cases using the log would be faster , and more direct.
you do have to check for 0 though and avoid taking the log of 0, as that would cause the program to crash.