Perl Weekly Challenge 149: Fibonacci Digit Sum

by Abigail

Challenge

Given an input $N, generate the first $N numbers for which the sum of their digits is a Fibonacci number.

Example

f(20)=[0, 1, 2, 3, 5, 8, 10, 11, 12, 14, 17, 20, 21, 23, 26, 30, 32, 35, 41, 44]

Discussion

This is sequence A028840 in The On-Line Encyclopedia of Integer Sequences.

Solution

We need to do two things: given a number, find the sum of its digits, and given a number, check whether that number if a Fibonacci number.

The first taks is similar to what was needed in week 133, so we can reuse the code.

Perl

First, we create a method which, given a (non-negative) integer, returns the sum of its digit. We do this by getting the digits one at a time, from the right, using modulus and integer division:

sub digitsum ($number) {
    my $sum  =  0;
    my $base = 10;
    while ($number > 0) {
        use integer;
        $sum    += $number % $base;
        $number /= $base;
    }
    return $sum;
}

To check whether a number is a Fibonacci number, we keep a hash which contains Fibonacci numbers. If we have a number N of which we want to know whether it's a Fibonacci number, we first check what the largest number in our hash is. If it's less than N, we generate successive numbers until we reach or exceed N. Then we do a simple look up.

sub is_fib ($n) {
    state  $fib = {0 => 1, 1 => 1};
    state  $fib_prev = 0; 
    state  $fib_last = 1; 
    while ($fib_last < $n) {
        ($fib_prev, $fib_last) = ($fib_last, $fib_prev + $fib_last);   
        $$fib {$fib_last}      = 1;
    }
    $$fib {$n}
}

We can then print the numbers in a simple loop:

while (<>) {
    for (my ($k, $N) = (0, 0 + $_); $N > 0; $k ++) {
        $N --, print "$k " if is_fib digitsum $k
    }
    print "\n";
}

Find the full program on GitHub.

Bc

bc doesn't have hashes. So, we keep the generated Fibonacci numbers in an array. Once we have generated enough, we will do a binary search to see whether the input number is a Fibonacci or not.

fib_prev  = 1       
fib_last  = 1       
fib [0]   = 0
fib [1]   = 1
fib_count = 2

define is_fib (n) {
    auto t, min, max
    while (fib_last < n) {
        t        = fib_last
        fib_last = fib_prev + fib_last
        fib_prev = t
        fib [fib_count] = fib_last
        fib_count = fib_count + 1
    }
    min = 0
    max = fib_count
    while (min < max) {
        mid = (min + max) / 2
        if (fib [mid] == n) {
            return (1)
        }
        if (fib [mid] < n) {
            min = mid + 1
        } else {
            max = mid
        }
    }
    return (0)
}

Find the full program on GitHub.

Scheme

For our Scheme solution, we use a recursive solution to calculate the sum of the digits of a number:

(define (digit_sum n)
    (define base 10)
    (if (= n 0) 0 (+ (modulo n base) (digit_sum (floor/ n base)))))

To check if a number is a Fibonacci number, this time, we're not storing numbers generated so far. We use pure recursion:

(define (_is_fib n prev last)
    (cond ((= n prev) #t)
          ((< n prev) #f)
          (else (_is_fib n last (+ last prev)))))

(define (is_fib n) (_is_fib n 0 1))

Since recursion is the name of the game in Scheme, we use recursion for the loop which prints out the numbers:

(define (digit_fib k n)
    (cond ((= n 0) #f)
          ((is_fib (digit_sum k))
             (begin (format #t "~d " k) (digit_fib (+ k 1) (- n 1))))
          (else (digit_fib (+ k 1) n))))

Here, k is the first number to check, and n is the amount of numbers we still want to check. The main program (also recursive) looks like this:

(define (main)
    (define n (read-line))
    (define k 0)
    (if (not (eof-object? n))
        (begin
            (digit_fib 0 (string->number n))
            (newline)
            (main))))

Find the full program on GitHub.

Other languages

We also have implementations, all similar to the Perl one, in:

AWK, Bash, C, Go, Java, Lua, Node.js, Pascal, Python, R, Ruby, and Tcl.


Please leave any comments as a GitHub issue.