Performance of fmt.Scanf() in golang - performance

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?

Related

Golang gives different result everytime using map for AOC 2021 Day 6 problem

I've been trying to solve Advent of Code 2021 and in day 6, I am trying this solution but the result is different everytime. What seems to be the problem? Is there any memory leakage with map?
The input file can be found here
The details of the problem can be read here
For part one it was straight-forward looping over arrays but as the number of days increases, the population grows exponentially and the time complexity grows in similar manner.
with go version go1.19.3
I have tried this:
package main
import (
"fmt"
"os"
"strconv"
"strings"
)
func getInput() []int {
var parsedData []int
rawData, _ := os.ReadFile("input.txt")
data := strings.Split(string(rawData), ",")
for _, strNum := range data {
num, _ := strconv.Atoi(strNum)
parsedData = append(parsedData, num)
}
return parsedData
}
func main() {
data := getInput()
var total int64
// create a map t0 hold the number of fish with the same timer
fishWithSameTimer := make(map[int]int64)
for _, timer := range data {
if _, ok := fishWithSameTimer[timer]; ok {
fishWithSameTimer[timer] += 1
} else {
fishWithSameTimer[timer] = 1
}
}
const days int = 18
currDay := 1
for currDay <= days {
tempFishTimerData := make(map[int]int64)
for timer, numOfFishes := range fishWithSameTimer {
if timer == 0 {
tempFishTimerData[8] = numOfFishes
tempFishTimerData[6] = numOfFishes
}else{
tempFishTimerData[timer - 1] += numOfFishes
}
}
fishWithSameTimer = tempFishTimerData
fmt.Println("Day:", currDay, fishWithSameTimer)
currDay++
}
fmt.Println(fishWithSameTimer)
for _, num := range fishWithSameTimer {
total += num
}
fmt.Println(total)
}
Can anyone help?
I hope this piece of code does the work, please add the input file reading part and print the output slice as comma separated string. You can also validate if the input has all numbers between 0 and 8.
package main
import "fmt"
func refreshTimer(x int) (int, bool) {
if x == 0 {
return 6, true
} else {
return x - 1, false
}
}
func spawnFish(i []int) []int {
var parentIntTimer []int
var childIntTimer []int
for _, d := range i {
y, c := refreshTimer(d)
parentIntTimer = append(parentIntTimer, y)
if c {
childIntTimer = append(childIntTimer, 8)
}
}
return append(parentIntTimer, childIntTimer...)
}
func main() {
initialFishes := []int{3, 4, 3, 1, 2}
var spFishes []int
noOfDays := 18
for i := 1; i <= noOfDays; i++ {
spFishes = spawnFish(initialFishes)
initialFishes = spFishes
}
fmt.Println(spFishes)
}
Output: [6 0 6 4 5 6 0 1 1 2 6 0 1 1 1 2 2 3 3 4 6 7 8 8 8 8]

is power of 2 with golang

I want to check whether the number given is a power of 2. I have written a code but I cannot return true or false, I think somewhere there is an infinite loop. I am only allowed to use functions from imported packages on the code. I could not figure out what to do to correct the mistake. I would be glad if you can help me :)
package main
import (
"os"
"strconv"
)
func main() {
for len(os.Args) == 2 {
numbers, err := strconv.Atoi(os.Args[1])
if err != nil {
panic(err)
}
newnum := numbers
counts := 0
for numbers != 1 {
if newnum%2 != 0 {
} else {
newnum = newnum / 2
}
counts++
}
var x int = 2 ^ counts
if x == numbers {
return true
} else {
return false
}
}
}
`
As commented by #phuclv , I have created a sample program for your scenario by using n & (n - 1) == 0 as follows :
//Let's assume n = 16(00010000)
//Now find x = n-1 => 15(00001111) => x & n => 0
func CheckPowerOfTwo(n int) int {
//added one corner case if n is zero it will also consider as power 2
if n==0{
return 1
}
return n & (n - 1)
}
func main() {
var n = 16
flag := CheckPowerOfTwo(n)
if flag == 0 {
fmt.Printf("Given %d number is the power of 2.\n", n)
} else {
fmt.Printf("Given %d number is not the power of 2.\n", n)
}
}
You can run it here : https://go.dev/play/p/9cRWwiFAIn8

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 convert big.Float to big.Int

convert big.Float to big.Int, i write code below, but it overflow with uint64, so what's the correct way to cenvert big.Float to big.Int.
package main
import "fmt"
import "math/big"
func FloatToBigInt(val float64) *big.Int {
bigval := new(big.Float)
bigval.SetFloat64(val)
coin := new(big.Float)
coin.SetInt(big.NewInt(1000000000000000000))
bigval.Mul(bigval, coin)
result := new(big.Int)
f,_ := bigval.Uint64()
result.SetUint64(f)
return result
}
func main() {
fmt.Println("vim-go")
fmt.Println(FloatToBigInt(float64(10)))
fmt.Println(FloatToBigInt(float64(20)))
fmt.Println(FloatToBigInt(float64(30)))
fmt.Println(FloatToBigInt(float64(40)))
fmt.Println(FloatToBigInt(float64(50)))
fmt.Println(FloatToBigInt(float64(100)))
fmt.Println(FloatToBigInt(float64(1000)))
fmt.Println(FloatToBigInt(float64(10000)))
}
A big int bigger than uint64 will always cause an overflow as uint64 has fixed size. You should use the following method on *Float:
func (*Float) Int
The changes required would be:
func FloatToBigInt(val float64) *big.Int {
bigval := new(big.Float)
bigval.SetFloat64(val)
// Set precision if required.
// bigval.SetPrec(64)
coin := new(big.Float)
coin.SetInt(big.NewInt(1000000000000000000))
bigval.Mul(bigval, coin)
result := new(big.Int)
bigval.Int(result) // store converted number in result
return result
}
Working example: https://play.golang.org/p/sEhH6iPkrK
Use the function Float.Int(nil)
I have worked with a regular float64 number (not big.Float) and found out that conversion via string is the most precise way. Check it out
Note: the example is for float64 -> decimal(,20) conversion.
func bigIntViaString(flt float64) (b *big.Int) {
if math.IsNaN(flt) || math.IsInf(flt, 0) {
return nil // illegal case
}
var in = strconv.FormatFloat(flt, 'f', -1, 64)
const parts = 2
var ss = strings.SplitN(in, ".", parts)
// protect from numbers without period
if len(ss) != parts {
ss = append(ss, "0")
}
// protect from ".0" and "0." values
if ss[0] == "" {
ss[0] = "0"
}
if ss[1] == "" {
ss[1] = "0"
}
const (
base = 10
fraction = 20
)
// get fraction length
var fract = len(ss[1])
if fract > fraction {
ss[1], fract = ss[1][:fraction], fraction
}
in = strings.Join([]string{ss[0], ss[1]}, "")
// convert to big integer from the string
b, _ = big.NewInt(0).SetString(in, base)
if fract == fraction {
return // ready
}
// fract < 20, * (20 - fract)
var (
ten = big.NewInt(base)
exp = ten.Exp(ten, big.NewInt(fraction-int64(fract)), nil)
)
b = b.Mul(b, exp)
return
}
https://play.golang.org/p/_lkyQ_0udjd

How to use Math/Big in Go Lang

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))
}

Resources