Wednesday 12 June 2013

Exploring the times tables with Haskell

Ellie couldn't sleep and had noticed that the digits of the 8 times table decline, in the way that the digits of the nine times table always add to nine.

Explore in Haskell

We will need a generator for a times table series

times n = [n * x | x <- [1..]]

gives:

*Main> times 3
[3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105,108,111,114,117,120,123,126,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,189,192,195,198,201,204,207,210,213,216,219,222,225,228,231,234,237,240,243,246,249,252,255,258,261,264,267,270,273,276,279,282,285,288,291,294,297,300,303,306,309,312,315,318,321,324,327,330,333,336,339,342,345,348,351,354,357,360,363,366,369,372,375,378,381,384,387,390,393,396,399,402,405,408,411,414,417,420,423,426,429,432,435,438,441,444,447,450,453,456,459,462,465,468,471,474,477,480,483,486,489,492,495,498,501,504,507,510,513,516,519,522,525,528,531,534,537,540,543,546,549,552,555,558,561,564,567,570,573,576,579,582,585,588,591,594,597,600,603,606,609,612,615,618,621,624,627,630,633,636,639,642,645,648,651,654,657,660,663,666,669,672,675,678,681,684,687,690,693,696,699,702,705,708,711,714,717,720,723,726,729,732,735,738,741,744,747,750,753,756,759,762,765,768,771,774,777,780,783,786,789,792,795,798,801,804,807,810,813,816,819,822,825,828,831,834,837,840,843,846,849,852,855,858,861,864,867,870,873,876,879,882,885,888,891,894,897,900,903,906,909,912,915,918....

just the first 12

take 12 $ times 3

gives

[3,6,9,12,15,18,21,24,27,30,33,36]

We want each number as a list of its digits:

listdigits n = if n < 10 then [n] else (listdigits (n `div` 10)) ++ (listdigits (n `mod` 10))               

gives:

*Main> listdigits 12345
[1,2,3,4,5]

Add the list together

sumdigits n = sum $ listdigits n                                 

gives:

*Main> sumdigits 12345
15

what we are after is a single number, so recurse

onedigit n = if n < 10 then n else onedigit $ sumdigits n                                                   

gives:

*Main> onedigit 12345
6

now we can repeat for as far though the times table as we want, we expect repeated nines for the nine times table:

do_of n l = map onedigit (take l (times n))                                                                 
*Main> do_of 9 100 
[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9]                                                                                                            

the answer to Ellie's original hypothesis, the eights do repeatedly decline:

*Main> do_of 8 100 
[8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1,9,8]

Next we want to display this and other series...

Setup Haskell Plotting

Plotting is not simple, plotting in Haskell is worse. Setup separated into its own post as it took a while.

Once plotting is setup:

main = do 
    plotListsStyle 
        [Title "Multiplication Series Reduced - For Ellie"] 
        [(PlotStyle LinesPoints $ DefaultStyle x ,  (onedigit_tuple x)) | x <- [2..9]] 

we get:

Customise the line labels:

main = do 
   plotListsStyle 
      [Title "Multiplication Series Reduced - for Ellie", 
       YLabel "Reduction", 
       XLabel "Times"] 
      [ (PlotStyle{plotType=LinesPoints, lineSpec=(CustomStyle [LineTitle $ show x])}, (onedigit_tuple x)) | x <- [2..9]]

The whole program

import Graphics.Gnuplot.Simple

listdigits :: Integer-> [Integer]
listdigits n = if n < 10 then [n] 
                         else (listdigits (n `div` 10)) ++ (listdigits (n `mod` 10))

sumdigits :: Integer -> Integer
sumdigits n = sum $ listdigits n 

onedigit :: Integer -> Integer
onedigit n = if n < 10 then n else onedigit (sumdigits n)

onedigit_tuple :: Integer -> [(Integer, Integer)]
onedigit_tuple n = [(x, onedigit( n*x ) ) | x <- [1..19]]

main = do 
   plotListsStyle 
      [Title "Multiplication Series Reduced - for Ellie", 
       YLabel "Reduction", 
       XLabel "Times", 
       Key $ Just ["outside"]] 
      [(PlotStyle{plotType=LinesPoints, 
                  lineSpec=(CustomStyle [LineTitle $ show x])}, 
        (onedigit_tuple x)) | x <- [2..9]]

No comments:

Post a Comment