Reputation:
I'm working on a function that adds up all of the digits in a number, and to keep adding up digits until the number is reduced to a single digit. For example, the number 99999999999
should be evaluated like this:
99999999999
9+9+9+9+9+9+9+9+9+9+9
99
9+9
18
1+8
9
However, when I try running the number 99999999999
through my function, it returns 7
, even though it should return 9
. I've gone over my code several times, and I can't think of any reason why.
Here's the code:
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"
Upvotes: 0
Views: 1184
Reputation: 54574
[Edit]
If you are only interested in the result of the repeated application until one digit remains, of course Daniel Fischer is right, and you should use his solution. It might be still instructive how to deal with this kind of problem if such a shortcut isn't possible, hence I leave my old answer.
[/Edit]
You got the answer, but two remarks:
digitToInt
in Data.Char
, which is your read1
.
f 0 = 0
f y = (y `mod` 10) + f (y `div` 10)
Or the slightly cryptic version:
f = sum . map (`mod` 10) . takeWhile (> 0) . iterate (`div` 10)
If you're really concerned with speed, you can use divMod
, and you can try if accumulators are faster, e.g.
f n = go n 0 where
go 0 s = s
go k s = go k' (s+s') where (k',s') = k `divMod` 10
Upvotes: 2
Reputation: 370112
This works fine for me on a 64-bit system. If you're on a 32 bit system, 99999999999 doesn't fit into an Int, so it will overflow and give you wrong results.
If you change the type to Integer, it should work.
Upvotes: 6