How to use Math/Big in Go Lang - go

I am trying to create a factorial program, but when the numbers get too big the answer becomes wrong. Here is my code. I am new to math/big and cannot figure out how to correctly implement it into the program. Any help is appreciated. Thanks.
package main
import (
"fmt"
"os"
"strconv"
"math/big"
)
func main() {
fmt.Print("What integer would you like to to find a total factorial for?")
var userinput string
var userint int
fmt.Scan(&userinput)
userint, err := strconv.Atoi(userinput)
if err != nil {
fmt.Println("ERROR: Please input an integer")
os.Exit(2)
}
var efactorial int = 1
var ofactorial int = 1
var tfactorial int
var counter int
for counter = 2; counter <= userint; counter = counter + 2 {
efactorial = efactorial * counter
}
for counter = 1; counter <= userint; counter = counter + 2 {
ofactorial = ofactorial * counter
}
fmt.Println("Even factorial is: ", efactorial)
fmt.Println("Odd factorial is: ", ofactorial)
tfactorial = efactorial + ofactorial
fmt.Println("The Total factorial is: ", tfactorial)
}

You can use big.Int.MulRange to find the product of a range of integers. This is ideal for computing factorials. Here's a complete example that computes 50!
package main
import (
"fmt"
"math/big"
)
func main() {
var f big.Int
f.MulRange(1, 50)
fmt.Println(&f)
}
The output:
30414093201713378043612608166064768844377641568960512000000000000

you want ofactorial and tfactorial to be of type big.Int
ofactorial := big.NewInt(1)
tfactorial := big.NewInt(0)
Then you will want to use the methods from the big package for multiplying Ints found here
your for loop will look something like
for counter = 2; counter <= userint; counter = counter + 2 {
efactorial.Mul(efactorial * big.NewInt(counter))
}

Related

Performance of fmt.Scanf() in golang

I am trying to implement my python code in go. Here is a python code to find the inverse factorial of a large digit.
def largeInverseFactorial(n):
len_n = len(n)
i = 1
ans = 1
while True:
ans += math.log10(i)
if ans >= len_n:
return i
i += 1
Here is the go code after translating:
func largeInverseFactorial(n string) int64 {
len_n := float64(len(n))
var i float64 = 1
var ans float64 = 1
for true {
ans += math.Log10(i)
if ans >= len_n {
return int64(i)
}
i += 1
}
return 0
}
I need this go code to work with string of digits where its length can go up to 10^6. But to my surprise the go code is more than 20 times slower than its python counterpart. Can anybody tell me what am I missing in go or what's the reason behind it.
Update: The problem seems on the other side. So after using bufio.NewReader(os.Stdin).ReadString('\n') the code worked well and there is no wrong in for loop which was my original thought. Here is the code it worked:
package main
import (
"bufio"
"fmt"
"math"
"os"
"strconv"
"strings"
)
func smallInverseFactorial(value string) int64 {
var pre, ans int64
pre = 1
ans = 1
intVal, _ := strconv.ParseInt(value, 10, 64)
if intVal == 1 {
return 1
}
for ans < intVal {
ans *= pre
pre += 1
}
return pre - 1
}
func largeInverseFactorial(n string) int64 {
len_n := float64(len(n))
var i float64 = 1
var ans float64 = 1
for {
ans += math.Log10(i)
if ans >= len_n {
return int64(i)
}
i += 1
}
return 0
}
func main() {
var value string
value, _ = bufio.NewReader(os.Stdin).ReadString('\n')
value = strings.Split(value, "\n")[0]
// fmt.Scanf("%s", &value)
if len(value) < 3 {
fmt.Println(smallInverseFactorial(value))
} else {
fmt.Println(largeInverseFactorial(value))
}
}
So my question why using fmt.Scanf() is super slow when input gets larger?

Golang Simple User Input Product Math Question like 3*2*1 = 6

I'm trying to create a small program that allows a user to input an integer which will output the product such as follows:
For example:
a = 5, 5*4*3*2 = 120
a = 4, 4*3*2*1 = 24
a = 3, 3*2*1 = 6
Can someone provide guidance as I'm stuck on how to frame this more efficiently. If using Python, I would probably write the logic something like:
def a(num):
x = 1
for i in range (num):
x=x*(i + 1)
return x
print a(5)
You need to learn about the go language itself first, after that you'll be able to convert your python code into go, easily.
Few go learning resources:
https://tour.golang.org
https://gobyexample.com
https://golang.org/doc
But anyway, here is the go version of your python code:
func a(num int) int {
x := 1
for i := 0; i < num; i++ {
x = x * (i + 1)
}
return x
}
func main() {
fmt.Println(a(5)) // 120
fmt.Println(a(4)) // 24
fmt.Println(a(3)) // 6
}
Working playground: https://play.golang.org/p/glHwuMhTDYj
the main function taken from previous answer - only the scanf added here as you requested
package main
import (
"fmt"
)
func a(num int) int {
x := 1
for i := 0; i < num; i++ {
x = x * (i + 1)
}
return x
}
func main() {
var i int
_, err := fmt.Scanf("%d", &i)
if nil == err {
fmt.Println(a(i))
} else {
panic(err)
}
}

Golang number base conversion

I was wondering, how do you convert a base10 number from one base to another without usage of strconv in Golang ?
Could you please give me some advice ?
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println(big.NewInt(1000000000000).Text(62))
}
Demo
Use the math package and a log identify:
log_77(x) = log(x) / log(77)
This is probably cheating but I guess you could look at the implementation of strconv.FormatInt, and build some of your own code using that as an example. That way you aren't using it directly, you have implemented it yourself.
You can use this function to convert any decimal number to any base with the character set of your choice.
func encode(nb uint64, buf *bytes.Buffer, base string) {
l := uint64(len(base))
if nb/l != 0 {
encode(nb/l, buf, base)
}
buf.WriteByte(base[nb%l])
}
func decode(enc, base string) uint64 {
var nb uint64
lbase := len(base)
le := len(enc)
for i := 0; i < le; i++ {
mult := 1
for j := 0; j < le-i-1; j++ {
mult *= lbase
}
nb += uint64(strings.IndexByte(base, enc[i]) * mult)
}
return nb
}
You can use it like that:
// encoding
var buf bytes.Buffer
encode(100, &buf, "0123456789abcdef")
fmt.Println(buf.String())
// 64
// decoding
val := decode("64", "0123456789abcdef")
fmt.Println(val)
// 100

How to adjust the size of two-dimensional array in Go?

I have written a program that reads input lines and checks if a line begins with #.
If so, the current line and the next one will be saved in two columns in the same row in a two-dimensional array:
Go Playground
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
var multiDimArr [3][2]string
var lineCount int
scanner := bufio.NewScanner(strings.NewReader(input))
for line := 0; scanner.Scan(); line++ {
if strings.HasPrefix(scanner.Text(), "#") {
multiDimArr[line][0] = scanner.Text()
scanner.Scan()
multiDimArr[line][1] = scanner.Text()
lineCount++
}
}
for i := 0; i < lineCount; i++ {
for j := 0; j < 2; j++ {
fmt.Printf("multiDimArr[%d][%d] = %s\n", i, j, multiDimArr[i][j])
}
}
}
Output:
multiDimArr[0][0] = #FooBar1
multiDimArr[0][1] = FooBar1
multiDimArr[1][0] = #Foobar2
multiDimArr[1][1] = FooBar2
multiDimArr[2][0] = #FooBar3
multiDimArr[2][1] = FooBar3
My problem is that I need to know the number of lines in the input when building the program, so I can adjust the size of multiDimArr.
Can I do anything to make it take any number of lines?
Try this variation:
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
var multiDimArr [][2]string
scanner := bufio.NewScanner(strings.NewReader(input))
for scanner.Scan() {
if strings.HasPrefix(scanner.Text(), "#") {
firstLine := scanner.Text()
scanner.Scan()
secondLine := scanner.Text()
multiDimArr = append(multiDimArr, [2]string{firstLine, secondLine})
}
}
for i, row := range multiDimArr {
for j, line := range row {
fmt.Printf("multiDimArr[%d][%d] = %s\n", i, j, line)
}
}
}
Use this Slice: [][2]string{} , so you don't need to count the number of lines of input:
Try this working sample code:
package main
import "bufio"
import "fmt"
import "strings"
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
multiDimArr := [][2]string{}
for i, r := 0, bufio.NewScanner(strings.NewReader(input)); r.Scan(); i++ {
line1 := r.Text()
if !strings.HasPrefix(line1, "#") || !r.Scan() {
break
}
multiDimArr = append(multiDimArr, [2]string{line1, r.Text()})
}
fmt.Println(multiDimArr)
}
output:
[[#FooBar1 FooBar1] [#Foobar2 FooBar2] [#FooBar3 FooBar3]]
Also you may use this working sample code if you need to pre scan input to count the number of lines, using multiDimArr := make([][2]string, n) makes this slice [][2]string with length = capacity = n:
package main
import "bufio"
import "fmt"
import "strings"
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
n := 0
for r := bufio.NewScanner(strings.NewReader(input)); r.Scan() && strings.HasPrefix(r.Text(), "#") && r.Scan(); n++ {
}
multiDimArr := make([][2]string, n)
for i, r := 0, bufio.NewScanner(strings.NewReader(input)); r.Scan(); i++ {
line1 := r.Text()
if !strings.HasPrefix(line1, "#") || !r.Scan() {
break
}
multiDimArr[i] = [2]string{line1, r.Text()}
}
fmt.Println(multiDimArr)
}
Output:
[[#FooBar1 FooBar1] [#Foobar2 FooBar2] [#FooBar3 FooBar3]]
Array types:
The length is part of the array's type; it must evaluate to a
non-negative constant representable by a value of type int.
So you can't use array because its length is constant, using multiDimArr := [n][2]string{} makes compile time error: non-constant array bound n:
n := preScan(input)
//multiDimArr := [n][2]string{} // error: non-constant array bound n

Generating Random Numbers in Go

I am trying to generate random numbers (integers) in Go, to no avail. I found the rand package in crypto/rand, which seems to be what I want, but I can't tell from the documentation how to use it. This is what I'm trying right now:
b := []byte{}
something, err := rand.Read(b)
fmt.Printf("something = %v\n", something)
fmt.Printf("err = %v\n", err)
But unfortunately this always outputs:
something = 0
err = <nil>
Is there a way to fix this so that it actually generates random numbers? Alternatively, is there a way to set the upper bound on the random numbers this generates?
Depending on your use case, another option is the math/rand package. Don't do this if you're generating numbers that need to be completely unpredictable. It can be helpful if you need to get results that are reproducible, though -- just pass in the same seed you passed in the first time.
Here's the classic "seed the generator with the current time and generate a number" program:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().Unix())
fmt.Println(rand.Int())
}
crypto/rand provides only binary stream of random data, but you can read integers from it using encoding/binary:
package main
import "encoding/binary"
import "crypto/rand"
func main() {
var n int32
binary.Read(rand.Reader, binary.LittleEndian, &n)
println(n)
}
As of 1 april 2012, after the release of the stable version of the lang, you can do the following:
package main
import "fmt"
import "time"
import "math/rand"
func main() {
rand.Seed(time.Now().UnixNano()) // takes the current time in nanoseconds as the seed
fmt.Println(rand.Intn(100)) // this gives you an int up to but not including 100
}
You can also develop your own random number generator, perhaps based upon a simple "desert island PRNG", a Linear Congruential Generator. Also, look up L'Ecuyer (1999), Mersenne Twister, or Tausworthe generator...
https://en.wikipedia.org/wiki/Pseudorandom_number_generator
(Avoid RANDU, it was popular in the 1960's, but the random numbers generated fall on 15 hyperplanes in 3-space).
package pmPRNG
import "errors"
const (
Mersenne31 = 2147483647 // = 2^31-1
Mersenne31Inv = 1.0 / 2147483647.0 // = 4.656612875e-10
// a = 16807
a = 48271
)
// Each stream gets own seed
type PRNGStream struct {
state int
}
func PRNGStreamNew(seed int) *PRNGStream {
prng := (&PRNGStream{})
prng.SetSeed(seed)
return prng
}
// enforce seed in [1, 2^31-1]
func (r*PRNGStream) SetSeed(seed int) error {
var err error
if seed < 1 || seed > Mersenne31 {
err = errors.New("Seed OOB")
}
if seed > Mersenne31 { seed = seed % Mersenne31 }
if seed < 1 { seed = 1 }
r.state = seed
return err
}
// Dig = Park-Miller DesertIslandGenerator
// integer seed in [1, 2^31-1]
func (r*PRNGStream) Dig(seed int) float32 {
xprev := r.state // x[i-1]
xnext := (a * xprev) % Mersenne31 // x[i] = (a*x[i-1])%m
r.state = xnext // x[i-1] = x[i]
Ri := float32(xnext) * Mersenne31Inv // convert Ui to Ri
return Ri
}
func (r*PRNGStream) Rand() float32 {
r.state = (uint64_t)*r.state * Multby % 0x7fffffff
return float32(r.state) * Mersenne31Inv
}
A few relevant links:
https://en.wikipedia.org/wiki/Lehmer_random_number_generator
You might use this function to update your x[i+1], instead of the one above,
val = ((state * 1103515245) + 12345) & 0x7fffffff
(basically, different values of a, c, m)
https://www.redhat.com/en/blog/understanding-random-number-generators-and-their-limitations-linux
https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf
https://www.math.utah.edu/~alfeld/Random/Random.html
https://learn.microsoft.com/en-us/archive/msdn-magazine/2016/august/test-run-lightweight-random-number-generation

Resources