6

我在项目 euler 做问题 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

4 回答 4

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

祝你好运!

于 2009-12-02T14:39:14.277 回答
3

对Haskell不太了解,但我会取立方根,四舍五入到最接近的整数,取立方,然后与原始值进行比较。

于 2009-12-02T14:02:26.997 回答
1

对于另一种对Integer值有用的方法,请查看arithmoi 包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
于 2014-02-10T00:09:57.027 回答
0

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

因此,您需要修复isCube才能在 s 上正常工作Integer

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

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

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

于 2009-12-02T14:40:11.817 回答