Haskell中可靠的立方根

Jon*_*FTW 6 haskell root

我正在项目euler 做问题62,并提出以下测试数字是否为立方数:

isInt x = x == fromInteger (round x)
isCube x= isInt $ x**(1/3)
Run Code Online (Sandbox Code Playgroud)

但由于浮点错误,它返回不正确的结果:

*Main> isCube (384^3)
False
Run Code Online (Sandbox Code Playgroud)

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

在旁注中,这是我的解决方案的其余部分,由于类型接口错误,它不起作用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]
Run Code Online (Sandbox Code Playgroud)

我需要做些什么来修复错误?

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

任何优化也是受欢迎的;-)

sve*_*son 8

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

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

isCube :: (RealFrac a, Floating a) => a -> Bool
Run Code Online (Sandbox Code Playgroud)

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

isCube x = isInt $ (fromIntegral x) ** (1/3)
Run Code Online (Sandbox Code Playgroud)

但是,这不会使您的程序正确.

让程序更正确的一种方法是做Henrik所建议的.它看起来像这样:

isCube x = (round (fromIntegral x ** (1/3))) ^ 3 == x
Run Code Online (Sandbox Code Playgroud)

祝好运!