将数字转换为他们的 log2

Convert number to their log2

提问人:Kokizzu 提问时间:9/25/2014 最后编辑:Kokizzu 更新时间:10/4/2014 访问量:611

问:

我需要将数字转换为最小的 log2 +1,但我有一个问题,在 32 位 Ruby 中,log2(8) = 2.99999999999999996

输入 () 和输出 () 应为:poslevel

1 -> 1
2-3 -> 2
4-7 -> 3
8-15 -> 4
16-31 -> 5
and so on..

我的公式:

pos = 8 
level = ( Math.log(pos,2) + 1 ).to_i
# 3 (wrong) in 32-bit Ruby
# 4 (correct) in 64-bit Ruby

是否有更多方法可以防止这种情况发生,或者是否有任何其他公式可以转换为正确的公式,如上所示?poslevel

Ruby Math 浮点精度

评论

0赞 Kokizzu 9/25/2014
是的,它只发生在特定数字上:8、64、4096、8192、16777216、67108864、281474976710656、2251799813685248等“___”)我不知道为什么
1赞 Bathsheba 9/25/2014
恐怕是浮点精度。就像饼干碎裂的方式一样。但这几乎是正确的,不是吗?
0赞 Kokizzu 9/25/2014
没有“___”) 1 到 3 之间的差异 4 使我的另一个算法变得有问题 XD
1赞 Bathsheba 9/25/2014
好吧,是那个算法出了问题。浮点很难使用。
1赞 sawa 9/25/2014
你的问题令人困惑。您似乎想要 log 的整数部分加 1。这是你的特殊问题。在这里提问时,请提取问题的核心/最小部分。要求日志,而不是日志加 1。

答:

2赞 sawa 9/25/2014 #1
pos = 8
level = 0
until pos < 2
  level += 1
  pos /= 2
end
level + 1 #=> 4
1赞 Patrick Oscity 9/25/2014 #2

这是计算整数底数的另一种有趣方法:

0.upto(Float::INFINITY).find{|e| x - base**e < base }

评论

0赞 Patrick Oscity 9/25/2014
尽管@sawa的答案应该表现得更好,因为它只对每个潜在指数进行一次除法,而我的答案对每个指数进行一次幂运算。
-1赞 Cary Swoveland 9/25/2014 #3

IEEE 754-2008 的最大可表示值为 ,因此存储在二进制 32 中的数字小于十进制 128。由于舍入误差是 1 的一小部分,我们可以四舍五入到最接近的整数,看看该整数的 2 次幂是否等于给定的数字。如果是这样,则返回整数幂;else return ,表示它不是 2 的幂。binary32(2−2**(−23)) × 2**127base 2 lognil

def log_2_if_integer(n)
  x = Math.log(n,2).round(0).to_i
  (2**x == n) ? x : nil
end

log_2_if_integer(4)   #=> 2
log_2_if_integer(512) #=> 9
log_2_if_integer(3)   #=> nil

换句话说,由于对数小于 128,因此舍入误差无法生成一个值,例如对于任何(正或负)整数。x2**(x+m) == nm != 0

评论

1赞 Teepeemm 9/25/2014
我认为 OP 想要一个答案,即使它不是 2 的幂:.8-15 -> 4
0赞 Cary Swoveland 9/26/2014
@Teepeemm,关于你的评论,我有两件事要说:1.你可以返回一个浮点数,而不是如果值不是 2 的幂,这不是很明显吗?2. 其他两个答案都没有检查数字是否是 2 的幂。我不是在责怪他们,因为我相信他们认为这样的检查是微不足道的。nil
0赞 Mark Dickinson 10/4/2014
“存储在二进制 32 中的数字的基数 2 对数不超过十进制 8”。这是不对的:可以以 IEEE 754 binary32 格式存储的最大数字接近 ,因此其以 2 为底的对数将接近 。我不确定我是否理解 binary32 格式与这个问题的相关性:Ruby 在引擎盖下没有使用双精度浮点数 (binary64) 吗?2^128128
0赞 Cary Swoveland 10/4/2014
@MarkDickinson,感谢您指出这一点。我当然搞砸了,但这并不影响该方法的有效性。OP 专门针对 32 位 Ruby。请看我的编辑。
0赞 Mark Dickinson 10/4/2014
我认为它是 32 位还是 64 位 Ruby 并不重要:无论哪种方式,它都会使用 binary64 格式。