0

数値のすべての桁を合計し、数値が1桁になるまで桁を加算し続ける関数に取り組んでいます。たとえば、番号は次の99999999999ように評価する必要があります。

99999999999
9+9+9+9+9+9+9+9+9+9+9
99
9+9
18
1+8
9

ただし、99999999999関数で数値を実行しようとすると、を返す7はずなのに、を返し9ます。私は自分のコードを何度か調べましたが、その理由は考えられません。

コードは次のとおりです。

sumdr x
  | x <= 9 = x
  | otherwise = sumdr $ addupnums x

addupnums y = foldl (+) 0 $ map read1 $ show y

read1 :: Char -> Int
read1 '1' = 1
read1 '2' = 2
read1 '3' = 3
read1 '4' = 4
read1 '5' = 5
read1 '6' = 6
read1 '7' = 7
read1 '8' = 8
read1 '9' = 9
read1 '0' = 0
read1 x = error "needs to be a number"
4

2 に答える 2

6

これは、64ビットシステムでは問題なく機能します。32ビットシステムを使用している場合、99999999999はIntに適合しないため、オーバーフローして間違った結果が得られます。

タイプを整数に変更すると、機能するはずです。

于 2012-05-16T20:53:04.870 に答える
2

[編集]

1桁が残るまで繰り返し適用した結果にのみ関心がある場合は、もちろんDaniel Fischerが正しいので、彼のソリューションを使用する必要があります。そのようなショートカットが不可能な場合でも、この種の問題に対処する方法はまだ有益かもしれません。したがって、私は古い答えを残します。

[/編集]

あなたは答えを得ました、しかし2つの意見:

  • Hoogleを使用すると、で関数digitToIntを見つけることができData.Charます。read1
  • 数字を取得するためだけに数値を文字列に変換するのは無駄に思えます。たとえば、もう少し数学がうまくいく場合です。

f 0 = 0
f y = (y `mod` 10) + f (y `div` 10)

または少し不可解なバージョン:

f = sum . map (`mod` 10) . takeWhile (> 0) . iterate (`div` 10)

速度に本当に関心がある場合は、を使用できますdivMod。また、アキュムレータの速度が速いかどうかを試すことができます。

f n = go n 0 where
  go 0 s = s
  go k s = go k' (s+s') where (k',s') = k `divMod` 10
于 2012-05-16T21:19:15.390 に答える