*Edit: I’m implementing a new version of this that isn’t limited by overflow. I’m doing this by adding the numbers on a per digit basis, carefully managing the overflow, and storing the numbers as strings. Theoretically, we should be able to calculate LARGE Fibonacci numbers like this.*

When I heard about Google’s new programming language Go last week, I immediately jumped on it. I had used Limbo before for a distributed programming course, so I thought that I might write some code to help other people get their feet wet.

My example is a simple Fibonacci number calculator. It works by creating a new Go-routine every time it needs to calculate the next number. There are a couple different approaches to doing this: Create the entire pipeline first (faster calculation, slower set up), Create the pipeline as we go (not a bad way to go, smaller overhead), or create a ring and have the calculation take place within the ring. Communication between the Go-routines and the main thread are handled via channels.

I heavily documented the code so that beginners might be able to make sense of what’s going on. If you have any questions, please leave a comment!

/*

* Name: fibonacci.go

* Date: November 16, 2009

* Author: Jack Slingerland (jack.slingerland@gmail.com)

*

* Description: This program is a Fibonacci number calculator.

* It may be invoked as follows: “./8.out [goal]”, where [goal]

* is the Fibonacci number that you want to computer. Currently

* the program is limited to the 46th Fibonacci number due to

* overflow, however a new implementation is in the works that

* won’t have that limitation. The real purpose of this program

* is to show how Go-routines work, and how communication and

* sychronization between them is handled using channels.

*/package main

import (

“os”;

“fmt”;

“strconv”;

)/*

* This ADT holds all the information needed to calculate the next

* Fibonacci number in the sequence. Current is the current index

* in the series (ex, 5 = We’re on the 5th number in the sequence).

* Goal is of course, the number in the sequence that we’d like to

* achieve.

*/

type fibonacci struct {

a int;

b int;

current int;

goal int;

}func main() {

//Check the command line arguments for sanity.

goal, err := checkArgs();

if(err != “”) {

fmt.Fprintf(os.Stdout, “Error: %s”, err);

os.Exit(1);

}//Special case: If the goal is 2 or less, the Fibonacci number is always

//1. This isn’t really worth creating channels + go routines for.

if(goal <= 2) {

fmt.Fprintf(os.Stdout, “Fibnonacci Value %d is: %d\n”, goal, 1);

} else {

//Construct two channels, the input channel acts as our communication

//between the Go routines. As you can see, it can be typed as an

//ADT(struct), which makes passing data REALLY easy between go routines.

//The final channel is for passing back the goal Fibonacci number to

//the main thread.

input := make(chan fibonacci);

final := make(chan int);//Create a new fibonacci object and set it’s values.

var x fibonacci;

x.a = 1;

x.b = 1;

x.current = 2;

x.goal = goal;//Create a new Go routine with the addNumber function. We pass it the

//two channels that were declared earlier. This is similiar to “spawn”

//in Limbo.

go addNumber(input, final);//The first addNumber() Go routine will block until it gets input from

//the input channel. So, we pass it our fibonacci object.

input <- x;//Now, we block and wait for the Go routines (addNumber()) to finish up

//and send us back the final value.

number := <- final;//Print the value out and we’re done!

fmt.Fprintf(os.Stdout, “Fibnonacci Value %d is: %d\n”, x.goal, number);

}

}/*

* The addNumber() function takes two channels as parameters. One is a

* channel of fibonacci, which holds information about which number to

* calculate and when to stop, and then a channel of type int, which will

* be used to send the final goal number back to the main thread.

*/

func addNumber(input chan fibonacci, final chan int) () {

//Block here and wait for input from the previous thread

//or the main thread, depending on the situation.

x := <- input;//Here we check to see if we have met our goal, if we

//have, we return the goal value back to the main thread

//via the final channel. Otherwise, we calculate the

//next number in the sequence.

if(x.current < x.goal) {

fib := x.a + x.b;//This is fun because you can assign multiple values at once.

//x.a <- x.b and x.b <- fib. 🙂

x.a, x.b = x.b, fib;

x.current = x.current + 1;//Make a new channel of type fibonacci so that we can communicate

//with the new Go routine that we are about to create.

output := make(chan fibonacci);//Pass the new Go routine the newly created channel, as well as the

//final channel that was passed in from the caller.

go addNumber(output, final);//Send the fibonacci object out on the channel.

output <- x;

} else {

//Send the goal value out on the channel back to main.

final <- x.b;

}

//Go routine dies now.

}/*

* The checkArgs() function is a great example of returning multiple

* values. We return an integer and a string to the caller, so handling

* errors is fairly straight forward.

*/

func checkArgs() (int, string) {

//Fetch the command line arguments.

args := os.Args;//Check the length of the arugments, return failure if that are too

//long or too short.

if((len(args) < 2) || (len(args) >= 3)) {

return -1, “Invalid number of arguments.\n”;

}//Convert the goal argument to an integer.

goal, err := strconv.Atoi(args[1]);//Make sure the conversion went correctly, otherwise return failure.

if(err != nil) {

return -1, “Invalid argument. Argument must be an integer.\n”;

}//Since this implementation is limited, make sure the user can’t go

//beyond the program’s limits.

if(goal > 46) {

return -1, “This program only calculates up to the 46th Fibonacci number.\n”;

}//Check the lower bound as well.

if(goal < 1) {

return -1, “Invalid range. Number must be >= 1.\n”;

}//On success, return the goal value and an empty string indicating

//that everything is good.

return goal, “”;

}