I'm learning Go and I started using the math/big
package to deal with arbitrary-length integer.
I wrote this program that computes the n-th Fibonacci number : (removed the import
s) :
func main() {
imax, _ := strconv.Atoi(os.Args[1])
var a, b, c big.Int
a.SetUint64(0)
b.SetUint64(1)
for i := 0; i < imax; i++ {
c.Set(&b)
b.Add(&b, &a)
a.Set(&c)
}
fmt.Println(a.String())
}
Here's the code for the C program :
int main(int argc, char** argv)
{
int imax = atoi(argv[1]);
mpz_t a, b, c;
mpz_inits(a, b, c, NULL);
mpz_set_ui(a, 0);
mpz_set_ui(b, 1);
int i = 0;
for (i = 0; i < imax; i++) {
mpz_swap(a, b);
mpz_add(b, a, b);
}
char* astr = NULL;
astr = mpz_get_str(NULL, 10, a);
printf("%s
", astr);
return EXIT_SUCCESS;
}
The Go program computes the term 100,000 in 0.1 second (average), while the C equivalent, using the GMP lib, runs in 0.04 second only. That's two times slower.
Is there a way to get the same performance in my Go program ?
Don't print to stdout, it's slow. What result do you get for this code?
package main
import (
"math/big"
"os"
"strconv"
)
func main() {
max, err := strconv.Atoi(os.Args[1])
if err != nil {
panic(err)
}
a, b := big.NewInt(0), big.NewInt(1)
for i := 0; i < max; i++ {
a.Add(a, b)
a, b = b, a
}
}
Go is not hand crafted assembler code.
Your value of 100,000 is too small for a reliable benchmark. Use 1,000,000 or another value that runs for at least ten seconds.
In general, GMP is faster because it's crafted for performance. Under the hood, you may find that it is partly written in assembly, which reduces functions' call overhead, may utilize some CPU instructions like ADX
and so on.
If you care about performance, then you could use mpz_fib_ui
routine, that would be even faster, as it gains from some math trickery.
The direct answer to your question is probably to use some Go's binding for GMP.