在 haskell 中将浮点数舍入为整数

Rounding a float to an int in haskell

欧拉计划第3题说:13195的质因数是5、7、13、29。 600851475143这个数的最大质因数是多少?

我做了一个惰性素数列表,然后我做了一个当它们小于 600851475143 的平方根时,测试每个素数看它是否是一个因数。

primes :: [Integer]
primes = sieve [2..]
    where
        sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]
primeFactors :: Integer -> Integer
primeFactors x = last $ filter (\y -> x `mod` y == 0) $ takeWhile (< floor (sqrt x)) $ primes

但是,我收到 (< floor (sqrt x)) 错误:

projecteuler.hs:34:70:
    No instance for (RealFrac Integer) arising from a use of `floor'
    Possible fix: add an instance declaration for (RealFrac Integer)
    In the second argument of `(<)', namely `floor (sqrt x)'
    In the first argument of `takeWhile', namely `(< floor (sqrt x))'
    In the expression: takeWhile (< floor (sqrt x))

projecteuler.hs:34:77:
    No instance for (Floating Integer) arising from a use of `sqrt'
    Possible fix: add an instance declaration for (Floating Integer)
    In the first argument of `floor', namely `(sqrt x)'
    In the second argument of `(<)', namely `floor (sqrt x)'
    In the first argument of `takeWhile', namely `(< floor (sqrt x))'

这很奇怪: :t floor 给我 (Integral b, RealFrac a) => a -> b,这意味着这个楼层应该返回一个整数。我如何添加实例声明(或采取任何必要的措施来解决这个问题?)

此外,非常感谢任何有关代码优化的建议:)

编辑:这已经解决了,现在我正在清理它。我已经将所有内容封装在 main 函数中,所以它看起来像这样:

p003primeFactors :: Integer -> [Integer]
p003primeFactors x = filter (\y -> x `mod` y == 0) $ takeWhile (\p -> p^2 <= x) $ primes
    where
        primes :: [Integer]
        primes = sieve [2..]
            where
                sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]

这是为这样的函数创建名称空间的最佳方式吗?

实际问题是第二个错误。 (第一个只是结果。)x 是一个 Integer,因此您不能对其调用 sqrt,因为它需要一个 Floating 实例。

尝试:

takeWhile (< floor (sqrt (fromIntegral x)))

这会将 x 从整数转换为浮点数,以便 sqrt 可以对其进行运算。