我为Haar小波变换编写了一个函数,因为输入是一个功率为2的List。我试图通过确保在执行转换之前List的长度是2的幂来进行错误检查。我正在比较列表长度的日志基数2,看它是否均匀出现(小数点右边没有)。我认为haskell中的if语句有一些问题我不熟悉其他语言。如果我不进行错误检查并且只是使用正确的参数调用haar,它就能完美地工作。
haar :: (Fractional a) => [a] -> [a]
haar xs = if logBase 2 (fromIntegral (length xs)) /= truncate (logBase 2 (fromIntegral (length xs)))
then error "The List must be a power of 2"
else haarHelper xs (logBase 2 (fromIntegral (length xs)))
haarHelper xs 1 = haarAvgs xs ++ haarDiffs xs
haarHelper xs level = haarHelper (haarAvgs xs ++ haarDiffs xs) (level - 1)
haarAvgs [] = []
haarAvgs (x:y:xs) = ((x + y) / 2.0) : haarAvgs xs
haarDiffs [] = []
haarDiffs (x:y:xs) = ((x - y) / 2.0) : haarDiffs xs
我收到以下错误消息:
functions.hs:52:13:
Ambiguous type variable `t' in the constraints:
`Floating t'
arising from a use of `logBase' at functions.hs:52:13-48
`Integral t'
arising from a use of `truncate' at functions.hs:52:53-99
Probable fix: add a type signature that fixes these type variable(s)
Failed, modules loaded: none.
答案 0 :(得分:4)
有一个更简单,更快速的实现来检查正整数是2的幂:
import Data.Bits
powerOfTwo' n = n .&. (n-1) == 0
(注意:这省略了n
为正的检查,假设我们可以依赖length
。
解释,好奇:
该算法依赖于唯一属性,即只有2的幂才有一个1位(根据定义),并且递减它们会反转所有低位:
2^n = 100000...
2^n - 1 = 011111...
这没有共同的位,使它们按位和零。
对于所有非幂的2,递减将至少保持最高1位不变,保持按位和结果非零。
(维基百科:Fast algorithm to check if a positive number is a power of two)
答案 1 :(得分:2)
haar :: (Fractional a) => [a] -> [a]
haar xs | r /= (truncate r) = error "The List must be a power of 2"
| otherwise = haarHelper xs (logBase 2 (fromIntegral (length xs)))
where r = logBase 2 (fromIntegral (length xs))
是的,看起来像截断的东西。如果使用haskell的语句如上所示,则更容易编写。可能会帮助调试一下。
我想我可能知道。我认为truncate返回一个int,其他数字是浮点数。
试试这个
haar :: (Fractional a) => [a] -> [a]
haar xs | r /= w = error "The List must be a power of 2"
| otherwise = haarHelper xs (logBase 2 (fromIntegral (length xs)))
where
r = logBase 2 (fromIntegral (length xs))
w = intToFloat (truncate r)
haarHelper xs 1 = haarAvgs xs ++ haarDiffs xs
haarHelper xs level = haarHelper (haarAvgs xs ++ haarDiffs xs) (level - 1)
haarAvgs [] = []
haarAvgs (x:y:xs) = ((x + y) / 2.0) : haarAvgs xs
haarDiffs [] = []
haarDiffs (x:y:xs) = ((x - y) / 2.0) : haarDiffs xs
intToFloat :: Int -> Float
intToFloat n = fromInteger (toInteger n)
答案 2 :(得分:1)
补充马特的答案:
haar :: (Fractional a) => [a] -> [a]
haar xs | r /= (fromIntegral $ truncate r) = error "The List must be a power of 2"
| otherwise = haarHelper xs r
where r = logBase 2 (fromIntegral (length xs))
fromIntegral
r
haarHelper xs r
的定义
醇>
答案 3 :(得分:0)
这是haar
的一个版本,我认为它会更好一些:
haar :: (Fractional a) => [a] -> [a]
haar xs = maybe (error "The List must be a power of 2")
(haarHelper xs)
(intLogBase 2 $ length xs)
intLogBase :: (Integral a) => a -> a -> Maybe Int
intLogBase b n = intLogBase' b 1 n
where
intLogBase' b p 1 = Just p
intLogBase' b p n
| r /= 0 = Nothing
| otherwise = intLogBase' b (p + 1) q
where (q, r) = quotRem n b
intBaseLog
是baseLog
的变体,适用于整数,如果给定的数字不是给定基数的幂,则返回Nothing
。否则它将返回Just
中包含的权力。与logBase
和truncate
不同,没有转换为浮点数:我们一直有整数。
哈尔的maybe
function有三个论点。它将评估它的最后一个参数,如果它是Nothing
,它将返回第一个参数(在这种情况下是错误)。如果最后一个参数的计算结果为Just
,它会将第二个参数应用于Just
内的事物并返回该参数。
答案 4 :(得分:0)
这里的问题与if表达无关。正如在其他答案中所提到的那样,你将“logBase(...)”与“truncate(logBase(...))”进行比较。一个返回一个Floating类型,另一个返回一个Integral类型。没有类型(在标准库中)实现这两个类,因此条件不能按原样进行良好类型化。
我在使用2的幂时偶尔使用的模式是保留2的幂列表,并检查该数字是否在该列表中。例如:
powersOfTwo :: [Integer]
powersOfTwo = iterate (*2) 1
isPowerOfTwo x = xInt == head (dropWhile (<xInt) powersOfTwo)
where xInt = toInteger x
我没有测试过,但我的直觉告诉我,对于大多数用途,这可能比“logBase 2”更快。即使不是,它也更合适,因为它不涉及任何浮点数学。特别是,即使修复了类型,你当前的方法也不会起作用:truncate (logBase 2 512) == truncate (logBase 2 550)
(编辑:虽然我想我最初写这篇文章时可能会误解你的意图,但我现在意识到你可能想检查一下通过比较截断版本与非截断版本,而不是通过与任何已知值进行比较,logBase 2(...)是否是精确整数值。