Haskell中可靠的立方根

时间:2009-12-02 13:40:45

标签: haskell root

我正在项目euler做question 62并提出以下内容来测试一个数字是否为立方数:

isInt x = x == fromInteger (round x)
isCube x= isInt $ x**(1/3)

但是由于浮点错误,它会返回错误的结果:

*Main> isCube (384^3)
False

有没有办法实现更可靠的立方体测试?

在旁注中,这是我的解决方案的其余部分,由于filter (isCube) (perms n)上的类型接口错误而无效:

cubes = [n^3|n<-[1..]]
perms n = map read $ permutations $ show n :: [Integer]
answer = head [n|n<-cubes,(length $ filter (isCube) (perms n)) == 5]

我需要做些什么才能解决错误?

No instances for (Floating Integer, RealFrac Integer)
   arising from a use of `isCube' at prob62.hs:10:44-49

也欢迎任何优化; - )

4 个答案:

答案 0 :(得分:8)

尽量避免使用浮点数,尤其是遇到涉及整数值的问题时。浮点数在舍入时存在问题,并且某些值(如1/3)无法准确表示。所以你得到神秘的答案并不奇怪。

首先,为了修复您的类型错误,您必须重新定义isCube。如果你检查它的类型签名,它看起来像这样:

isCube :: (RealFrac a, Floating a) => a -> Bool

请注意,它期望某个类Floating的内容作为其第一个参数。您的问题是您希望对整数值使用此函数,而整数不是Floating的实例。您可以像这样重新定义isCube以进行功能类型检查。

isCube x = isInt $ (fromIntegral x) ** (1/3)

然而,这不会使您的程序正确。

使程序更正确的一种方法是执行Henrik建议的操作。它看起来像这样:

isCube x = (round (fromIntegral x ** (1/3))) ^ 3 == x
祝你好运!

答案 1 :(得分:3)

对Haskell不太了解,但我会将立方根,圆形到nearerst整数,取出立方体,并与原始值进行比较。

答案 2 :(得分:1)

对于Integer值有用的另一种方法,请查看arithmoi package中的integerCubeRoot函数。

示例:

ghci> import Math.NumberTheory.Powers.Cube
ghci> let x = 12345^3333
ghci> length $ show x
13637
ghci> isCube x
True
ghci> isCube (x+1)
False
ghci> length $ show $ integerCubeRoot x
4546

答案 3 :(得分:0)

perms的类型为[Integer]isCube的类型为(RealFrac a, Floating a) => a -> Bool(您可以在GHCI中查看)。 RealFrac约束来自round xFloating约束来自x**(1/3)。由于Integer既不是RealFrac也不是FloatingisCube 不能用作Integer -> Bool。所以filter isCube (perms n)没有意义。

因此,您需要修复isCube才能在Integer s:

上正常使用
isCube x = isInt $ (fromInteger x)**(1/3)

事实上,isCube (384^3)甚至编译的原因是它“真的”意味着isCube ((fromInteger 384)^(fromInteger 3))

当然,由于浮点错误,这仍然会很糟糕。基本上,像在isInt中一样检查浮动数字是否相等,几乎总是一个坏主意。请参阅其他答案,了解如何进行更好的测试。