9

I've been trying to calculating 2^100 in Golang. I understand the limit of numeric type and tried using math/big package. Here's what I've tried but I can't figure out why it doesn't work.

I've used computation by powers of two method to calculate the exponentiation.

package main

import (
    "fmt"
    "math/big"
)

func main() {
    two := big.NewInt(2)
    hundred := big.NewInt(50)
    fmt.Printf("2 ** 100    is %d\n", ExpByPowOfTwo(two, hundred))
}

func ExpByPowOfTwo(base, power *big.Int) *big.Int {
    result := big.NewInt(1)
    zero := big.NewInt(0)
    for power != zero {
        if modBy2(power) != zero {
            multiply(result, base)
        }
        power = divideBy2(power)
        base = multiply(base, base)
    }
    return result
}

func modBy2(x *big.Int) *big.Int {
    return big.NewInt(0).Mod(x, big.NewInt(2))
}

func divideBy2(x *big.Int) *big.Int {
    return big.NewInt(0).Div(x, big.NewInt(2))
}

func multiply(x, y *big.Int) *big.Int {
    return big.NewInt(0).Mul(x, y)
}
Ye Lin Aung
  • 11,234
  • 8
  • 45
  • 51

5 Answers5

19

BigInt package allows you to calculate x^y in log time (for some reason it is called exp). All you need is to pass nil as a last parameter.

package main

import (
    "fmt"
    "math/big"
)

func main() {
    fmt.Println(new(big.Int).Exp(big.NewInt(5), big.NewInt(20), nil))
}

If you are interested how to calculate it by yourself, take a look at my implementation:

func powBig(a, n int) *big.Int{
    tmp := big.NewInt(int64(a))
    res := big.NewInt(1)
    for n > 0 {
        temp := new(big.Int)
        if n % 2 == 1 {
            temp.Mul(res, tmp)
            res = temp
        }
        temp = new(big.Int)
        temp.Mul(tmp, tmp)
        tmp = temp
        n /= 2
    }
    return res
}

or play with it on go playground.

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • That's true. It doesn't make much sense to take two `*big.Int` as the arguments. I like your approach. – Ye Lin Aung May 12 '15 at 05:22
  • @YeLinAung actually if at some point of time you will need big integers, you can modify it easily to do this. I wrote this function just to as a toy example, to make sure I understand the algorithm, but if need to use it somewhere in your production code, rather use default Exp method. – Salvador Dali May 12 '15 at 05:26
  • `new(big.Int).Exp(big.NewInt(int64(a)), big.NewInt(int64(n)), nil)` is faster (and could be improved to not realloc the result, like the rest of the `math/big` routines do). – Dave C May 12 '15 at 15:33
  • @DaveC if you would have read the whole answer, you would see that I wrote about it at the end. I included own implementation, because sometimes people learn how algorithms work and try to implement something by themself and in my opinion OP needed exactly this. – Salvador Dali May 12 '15 at 18:54
  • 1
    Yeah. I've been trying to solve the ProjectEuler problems with different approaches and trying learn go in the same time. That's why I am trying to implement the different `exponentiation`. On the other hand, I didn't notice the built-in method too. Thanks both of you. I've upvoted all the answers :) – Ye Lin Aung May 14 '15 at 05:59
  • shouldn't some Pow() function(s) be added to the go package "big" ? They would be handy! Any particular reason why Go authors did not add any pow() functions to that package? It exists in the math package for small numbers – Another Prog Jul 24 '17 at 04:03
13

For example,

package main

import (
    "fmt"
    "math/big"
)

func main() {
    z := new(big.Int).Exp(big.NewInt(2), big.NewInt(100), nil)
    fmt.Println(z)
}

Output:

1267650600228229401496703205376

Since it's a power of two, you could also do a bit shift:

package main

import (
    "fmt"
    "math/big"
)

func main() {
    z := new(big.Int).Lsh(big.NewInt(1), 100)
    fmt.Println(z)
}

Output:

1267650600228229401496703205376
peterSO
  • 158,998
  • 31
  • 281
  • 276
2

You are returning immediately if power % 2 == 0. Instead, you just want to get the result of base ** (power /2). Then multiply result * result, and if power is even then multiply base to that.

spalac24
  • 1,076
  • 1
  • 7
  • 16
2

To compute 2^100

package main

import (
    "fmt"
    "math/big"
)

func main() {
    n := big.NewInt(0)
    fmt.Println(n.SetBit(n, 100, 1))
}

Playground

1
package main

import(
    "fmt"
    "math/big"
)

func main() {

    bigx, power10 := new(big.Int), new(big.Int)
    var x int64
    bigx.SetInt64(x) //set x int64 to bigx
    power10.Exp(big.NewInt(10), bigx, nil) //power10 *big.Int points to solution

    str10 := power10.Text(10)
    fmt.Printf(str10) // print out the number and check for your self

}
t j
  • 7,026
  • 12
  • 46
  • 66