[英]'Infinite' precision reciprocal in Haskell
我需要生成一个无限的Haskell列表,其中包含一个整数的倒数的小数部分(以MSB优先顺序)的所有位(或单词)。 有没有一种简单的方法可以从标准库中执行此操作,还是需要实现牛顿迭代函数或类似函数?
我考虑过使用CReal,但是找不到提取位/字的方法。
还有更多有原则的方法,但是CReal当然可以做到。
> bit n = (`mod` 2) . floor . (*2**n)
> [bit i (pi :: CReal) | i <- [-1..10]]
[1,1,0,0,1,0,0,1,0,0,0,0]
> [bit i (5/8 :: CReal) | i <- [1..10]]
[0,1,0,1,0,0,0,0,0,0,0]
随时随地交换2
。 对于无限列表,迭代乘法可能会更便宜,因此:
> bits = map ((`mod` 2) . floor) . iterate (2*)
> take 10 (bits (5/8 :: CReal))
[0,1,0,1,0,0,0,0,0,0]
同样,您可以将2
换成您喜欢的任何基数。
在我的另一个答案中,我展示了如何使用CReal来做到这一点,以回答您是否可以做到这一点的问题。 但是我实际上并不认为这是一个好主意,因为它调用的功率超过了所需。 只是为了表达我对“更原则性”方法的想法,这就是我的想法:
bits :: Rational -> [Int]
bits n = whole : bits (2*frac) where
(whole, frac) = properFraction n
实际上:
> take 65 . bits $ 1/3
[0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1]
你会发现,这是比其他答案CReal方法显著更快。 即使您将其他答案从CReal切换到Rational,它也应该具有更好的内存性能,因为它将分数保持上限为1(而其他解决方案每次迭代增加〜1位)。 可以通过注意到它开始循环来使其变得更快。 这是一个以易于观察的方式返回循环的函数:
import Data.Set (Set)
import qualified Data.Set as S
data BitsRep
= Loop Rational [Int]
| Lollipop [Int] [Int]
deriving (Eq, Ord, Read, Show)
-- always returns a Lollipop when given an empty set
bitsRaw :: Set Rational -> Rational -> BitsRep
bitsRaw s n = case S.member n s of
True -> Loop n []
False -> case bitsRaw (S.insert n s) (2*frac) of
Lollipop prefix loop -> Lollipop (whole:prefix) loop
Loop n' loop -> (if n == n' then Lollipop [] else Loop n') (whole:loop)
where
(whole, frac) = properFraction n
如果您确实希望将其作为一个无限列表,则可以使用一个简短的包装器,并在达到循环点后显着减少所需的计算量:
bits :: Rational -> [Int]
bits n = prefix ++ cycle loop where
Lollipop prefix loop = bitsRaw S.empty n
经过一番修补后,我设法不依靠Rational / CReal来做到这一点:
recipBits :: Integer -> [Bool]
recipBits n = dblAndMod2 2
where dblAndMod2 :: Integer -> [Bool]
dblAndMod2 !r = let bit = r >= n
r' = 2 * (if bit then r - n else r)
in bit : dblAndMod2 r'
与使用迭代相比,使用显式递归可以获得适度的加速。 我不太担心它进入循环的位置,因为我使用的它是如此之大,以至于我永远都不会到达循环。 再次感谢您的帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.