提问人:Kokizzu 提问时间:9/25/2014 最后编辑:Kokizzu 更新时间:10/4/2014 访问量:611
将数字转换为他们的 log2
Convert number to their log2
问:
我需要将数字转换为最小的 log2 +1,但我有一个问题,在 32 位 Ruby 中,log2(8) = 2.99999999999999996
输入 () 和输出 () 应为:pos
level
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
是否有更多方法可以防止这种情况发生,或者是否有任何其他公式可以转换为正确的公式,如上所示?pos
level
答:
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**127
base 2 log
nil
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,因此舍入误差无法生成一个值,例如对于任何(正或负)整数。x
2**(x+m) == n
m != 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^128
128
0赞
Cary Swoveland
10/4/2014
@MarkDickinson,感谢您指出这一点。我当然搞砸了,但这并不影响该方法的有效性。OP 专门针对 32 位 Ruby。请看我的编辑。
0赞
Mark Dickinson
10/4/2014
我认为它是 32 位还是 64 位 Ruby 并不重要:无论哪种方式,它都会使用 binary64 格式。
评论