haskell - 在haskell中查找整数的位长
问题描述
我想在 Haskell 中找到一种类型的位长(即最高设置位的索引) - 就像Java或PythonIntegral
中的相应方法一样。
我能想到的最好的办法是使用右移进行二进制搜索,如下所示:
bitLength :: Bits a => a -> Int
bitLength x = fst $ until (\ (lo,hi) -> lo >= hi) bsIter (0, until test (*2) 1)
where test n = shiftR x n == zeroBits
bsIter (lo, hi)
| test mid = (lo, mid)
| otherwise = (succ mid, hi)
where mid = (lo + hi) `div` 2
但这感觉就像在重新发明轮子,并且Integer
通过利用底层表示的知识,对于非常大的 s 也可能更有效。
(注意,提供的bitSize 函数更多的是关于数字类型中的最大位数,这不是我这里需要的。)
解决方案
如果你想从一个 Integral 类型开始,这应该能够做到:
import Math.NumberTheory.Logarithms
bitLength :: Integral a => a -> Int
bitLength n = integerLog2 (fromIntegral n)
ghci下测试:
λ>
λ> bitLength 64
6
λ>
λ> bitLength 127
6
λ>
λ> bitLength 1
0
λ>
λ> bitLength 0
*** Exception: Math.NumberTheory.Logarithms.integerLog2: argument must be positive
CallStack (from HasCallStack):
error, called at src/Math/NumberTheory/Logarithms.hs:82:19 in integer-logarithms-1.0.3-L1fXvdNnENnEcLpMml0rI7:Math.NumberTheory.Logarithms
λ>
编辑:
关于您的评论,如果函数bitLength
要名副其实,它必须返回基于 1 的索引,而不是最高设置位的从零开始的索引。
所以一个适当更正的版本bitLength
是这样的:
import Math.NumberTheory.Logarithms (integerLog2')
bitLength :: Integral a => a -> Int
bitLength n =
if (n > 0) then (succ . integerLog2' . fromIntegral) $ n
else if (n == 0) then 0
else error "bitLength: negative input !"
在ghci下重新测试:
λ>
λ> bitLength 0
0
λ> bitLength 1
1
λ> bitLength 2
2
λ> bitLength 120
7
λ> bitLength (-1)
*** Exception: bitLength: negative input !
CallStack (from HasCallStack):
error, called at bitLength.hs:25:39 in main:Main
λ>
注意:另一方面,Bits
接口(class)似乎没有提供将手头的项目转换为 的简单方法Integer
,可能是因为现有的库实例Integral
要开始。
推荐阅读
- reactjs - 如何从自定义反应挂钩访问数据
- ios - 很快,我在 UIStackView 内的 UIView 内有一个 UIButton,但该按钮没有响应
- android - 小部件参数的参数无效?
- c# - C# 中用于启动警报的计时器 - 防止它在早上 8 点之前启动的条件
- javascript - 如何使用 Phaser 3 为任何屏幕尺寸创建响应式游戏?
- javascript - Web 客户端从 Firebase 云消息传递控制台接收重复的测试消息
- javascript - 一旦屏幕达到一定宽度,防止图像继续增长
- python - 如何从url解析xml
- c# - 如何防止 WebView2(基于边缘)打开一个新窗口
- azure - 创建资源组失败并显示“没有授权”