6

私はプロジェクトオイラーで質問62を行っており、数値が3次かどうかをテストするために次のことを思い付きました:

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)

ただし、それではプログラムが正しくなりません。

プログラムをより正確にする 1 つの方法は、Henrik が提案したことを実行することです。次のようになります。

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

幸運を!

于 2009-12-02T14:39:14.277 に答える
3

Haskellについてはよくわかりませんが、立方根を取り、最も近い整数に丸め、立方体を取り、元の値と比較します。

于 2009-12-02T14:02:26.997 に答える
0

permsタイプは[Integer]です。isCubeタイプがあり(RealFrac a, Floating a) => a -> Boolます(GHCIで確認できます)。RealFrac制約は から、制約は から来round xます。もでもないのでとしては使えません。だから意味がありません。Floatingx**(1/3)IntegerRealFracFloatingisCube Integer -> Boolfilter isCube (perms n)

したがって、 sisCubeで適切に動作するように修正する必要があります。Integer

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

isCube (384^3)実際、コンパイルさえする理由は、それが「本当に」意味するからisCube ((fromInteger 384)^(fromInteger 3))です。

もちろん、これでも浮動小数点エラーのためにうまく機能しません。基本的に、 で行うように、浮動小数点数が等しいかどうかをチェックすることはisInt、ほとんどの場合、悪い考えです。より良いテストを作成する方法については、他の回答を参照してください。

于 2009-12-02T14:40:11.817 に答える