## The Twelve Days Of Christmas

### December 25, 2012

If you calculated 78 gifts, try again. That’s the number of gifts given on the twelfth day, not the total number of gifts given over twelve days.

The sum of the numbers from 1 to n is n(n+1)/2; for n=12, that’s 78. But that is only the number of gifts given on the twelfth day.

The total number of gifts given on n days is the nth tetrahedral number. You can think of the triangle on a billiard table, with fifteen balls; stack ten balls on top of the fifteen, then stack six balls on top of the ten, then stack three balls on top of the six, and finally stack one ball on top of the three, for a total of 35 balls. In terms of our song, we have 1 gift on the first day, 2+1=3 gifts on the second day (a total of 4 gifts), 3+2+1=6 gifts on the third day (a total of 10 gifts), 4+3+2+1=10 gifts on the fourth day (a total of 20 gifts), 5+4+3+2+1=15 gifts on the fifth day (a total of 35 gifts), and so on.

The formula for the nth tetrahedral number is n(n+1)(n+2)/6, which is 364 for n=12. Here’s the program:

```(define (xmas n)   (* n (+ n 1) (+ n 2) 1/6))```

```> (xmas 12) 364```

You can run the program at http://programmingpraxis.codepad.org/Ti7hK8mt.

Merry Christmas!

Pages: 1 2

### 11 Responses to “The Twelve Days Of Christmas”

1. Dan said

This problem statement leaves some ambiguity, as the number of gifts given in N days depends exactly on which of the 12 days gifts were given. In addition to the parameter N, a consecutive range or non-consecutive set of days must be specified in order to know how many gifts were given in total.

2. Matthew Feng said

Gifts that day: 2**n-1 or n(n+1)/2

At least I think that is what it is, assuming the following:
2. The gifts received = n + n-1 + n-2 + n-3 + … + 1.

3. Matthew Feng said

An edit to my previous post, 2**n-1 doesn’t work, sorry.

4. Ben said

Not so elegant solutions, the first is recursive,

— recursive

crimbo presents 0 = presents
crimbo presents days = crimbo (presents + loot) (days-1)
where loot = sum [1..days]

twelve_days = crimbo 0

— using map

f a b = (a + b) * ((1 + (b – a)) / 2)
tolv_dager days = sum \$ map (f 1) [1..days]

*Main> twelve_days 12
364
*Main> tolv_dager 12
364.0

5. Ben E Oliver said

sum \$ map (\x -> (1+x) * (x/2)) [1..12]

6. […] The Twelve Days Of Christmas (programmingpraxis.com) […]

7. […] The Twelve Days Of Christmas (programmingpraxis.com) […]

8. Globules said
```import Data.List (genericLength, mapAccumL, intercalate)
import Data.Ratio
import RecMath.GaussElim
import System.Environment

-- For efficiency (and fun!), we can find a polynomial that is equivalent to the
-- function totalGifts.  We calculate the differences between successive values
-- of the function, differences of the differences, and so on.  For example,
-- using our 12 days problem:
--
--   n       1   2    3     4     5 ...
--   f(n)    1   4   10    20    35 ...
--   d(1)      3   6    10    15 ...
--   d(2)        3    4     5 ...
--   d(3)           1     1 ...
--   d(4)               0 ...
--
-- If the i'th difference is equal to 0 then we use the first i function values
-- to construct a linear system of equations to solve for the coefficients of
-- the polynomial.  The equations are generated by plugging into:
--
--   c   n^(i-1) + c   n^(i-2) + ... + c n + c  = f(n)
--    i-1           i-2                 1     0
--
-- the i different values.  In our 12 days problem, this leads to:
--
--     a +   b +  c + d =  1
--    8a +  4b + 2c + d =  4
--   27a +  9b + 3c + d = 10
--   64a + 16b + 4c + d = 20
--
-- Upon solving this system we get a=1/6, b=1/2, c=1/3 and d=0.  So, the
-- resulting polynomial is:
--
--   1/6 n^3 + 1/2 n^2 + 1/3 n
--
-- Of course, all of the above depends on the ability to represent our function
-- with a polynomial.
--
-- See http://www.math.cmu.edu/~bkell/21110-2010s/formula.html for more detail.

-- Given a function, f, and an initial value, i, return the coefficients of a
-- polynomial equivalent to the function.  It's assumed that f can be
-- represented by a polynomial.
coefs :: (Integral a, Integral b) => (a -> b) -> a -> [Rational]
coefs f i = let vs = values f i
sz = length vs
m = map (mkRow sz . fromIntegral . fst) vs
x = map (fromIntegral . snd) vs
in linearSolve m x
where mkRow len = scanl (*) 1 . replicate (len-1)

-- Given a function, f, and an initial value, i, return the list of pairs,
-- [(i, f(i)), (i+1, f(i+1)), ..., (n, f(n))], sufficient to allow the
-- calculation of the equivalent polynomial.
values :: (Integral a, Eq b, Num b) => (a -> b) -> a -> [(a, b)]
values f i = map (\k -> (k, f k)) [i..i+n-1]
where n = genericLength \$ last diffs
diffs = takeWhile ((/=0) . last) . tail . scanl step [] \$ map f [i..]
step = flip \$ scanl (-)

-- Evaluate a polynomial at a given value.  The polynomial is represented by a
-- list of coefficients.
eval :: (Num a, Integral b) => [a] -> b -> a
eval cs n = let n' = fromIntegral n in foldr (\l r -> l+n'*r) 0 cs

showRat :: Rational -> String
showRat r | denominator r == 1 = show \$ numerator r
| otherwise = show (numerator r) ++ "/" ++ show (denominator r)

showPoly :: [Rational] -> String
showPoly cs = let terms = snd \$ mapAccumL (\n c -> (n+1, term c n)) 0 cs
in intercalate " + " \$ filter (not . null) terms
where term 0 _ = ""
term c p = showRat c ++ "n^" ++ show p

--------------------------------------------------------------------------------

giftsOnDay = 0 : [n | i <- [1..], let n = i + giftsOnDay !! (i-1)]

main :: IO ()
main = do
args <- getArgs
tot = eval cs nDays
putStrLn \$ "The total number of gifts after " ++ show nDays ++ " days is "
++ showRat tot ++ "."
putStrLn \$ "A polynomial for the total number of gifts is " ++ showPoly cs
```

When run, this produces:

```\$ ./xmas 12
The total number of gifts after 12 days is 364.
A polynomial for the total number of gifts is 1/3n^1 + 1/2n^2 + 1/6n^3
\$
```
9. […] The Twelve Days Of Christmas (programmingpraxis.com) […]

10. […] The Twelve Days Of Christmas (programmingpraxis.com) […]