Haskell 中可靠的立方根

发布于 2024-08-13 04:30:58 字数 788 浏览 5 评论 0原文

我正在 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

也欢迎任何优化;-)

I am doing question 62 at project euler and came up with the following to test whether a number is cubic:

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

But due to floating point error, it returns incorrect results:

*Main> isCube (384^3)
False

Is there a way to implement a more reliable cube test?

On a side-note, here is the rest of my solution, which doesn't work because of a type interface error on 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]

What do I need to do to fix the error?

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

Any optimisations are also welcome ;-)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

甜心小果奶 2024-08-20 04:30:58

尽量避免使用浮点数,尤其是当您遇到涉及整数值的问题时。浮点数存在舍入问题,并且某些值(如 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

祝你好运!

Try to avoid using floating point numbers as much as possible, especially when you have a problem which concerns integer values. Floating point numbers have problems with rounding and that certain values (like 1/3) cannot be represented exactly. So it's no surprise that you get mysterious answers.

First of all, in order to fix your type error you have to redefine isCube. If you check it's type signature it looks like this:

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

Note that it expects something that is of class Floating as its first argument. Your problem is that you want to use this function on integer values and integers are not an instance of Floating. You can redefine isCube like this to make the function type check.

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

However, that will not make your program correct.

One way to make your program more correct is to do what Henrik suggested. It would look like this:

isCube x = (round (fromIntegral x ** (1/3))) ^ 3 == x

Good luck!

叹梦 2024-08-20 04:30:58

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

Don't know much about Haskell, but I would take the cube root, round to the nearerst integer, take the cube, and compare to the original value.

云醉月微眠 2024-08-20 04:30:58

对于对 Integer 值有用的另一种方法,请查看 arithmoi 包

例子:

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

For another approach useful for Integer values have a look at the integerCubeRoot function in the arithmoi package.

Example:

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
鱼窥荷 2024-08-20 04:30:58

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

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

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

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

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

perms has the type [Integer]. isCube has the type (RealFrac a, Floating a) => a -> Bool (as you can check in GHCI). The RealFrac constraint comes from round x, the Floating constraint comes from x**(1/3). Since Integer is neither RealFrac nor Floating, isCube can't be used as Integer -> Bool. So filter isCube (perms n) doesn't make sense.

So you need to fix isCube to work properly on Integers:

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

In fact, the reason isCube (384^3) even compiles is that it "really" means isCube ((fromInteger 384)^(fromInteger 3)).

Of course, this will still work badly due to floating point errors. Basically, checking floating numbers for equality, as you do in isInt, is almost always a bad idea. See other answers for explanation how to make a better test.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文