How to convert an int64 to int in Go? - go

In Go, what is the best strategy for converting int64 to int? I am having difficulty comparing the two
package main
import (
"math"
"strings"
"strconv"
)
type largestPrimeFactor struct {
N int
Result int
}
func main() {
base := largestPrimeFactor{N:13195}
max := math.Sqrt(float64(base.N))
maxStr := strconv.FormatFloat(max, 'E', 'G', 64)
maxShift := strings.Split(maxStr, ".")[0]
maxInt, err := strconv.ParseInt(maxShift, 10, 64)
if (err != nil) {
panic(err)
}
on this next line
for a := 2; a < maxInt; a++ {
if isPrime(a) {
if base.N % a == 0 {
base.Result = a
}
}
}
println(base)
}
func isPrime(n int) bool {
flag := false
max := math.Sqrt(float64(n))
maxStr := strconv.FormatFloat(max, 'E', 'G', 64)
maxShift := strings.Split(maxStr, ".")[0]
maxInt, err := strconv.ParseInt(maxShift, 10, 64)
if (err != nil) {
panic(err)
}
for a := 2; a < maxInt; a++ {
if (n % a == 0) {
flag := true
}
}
return flag
}

You convert them with a type "conversion"
var a int
var b int64
int64(a) < b
When comparing values, you always want to convert the smaller type to the larger. Converting the other way will possibly truncate the value:
var x int32 = 0
var y int64 = math.MaxInt32 + 1 // y == 2147483648
if x < int32(y) {
// this evaluates to false, because int32(y) is -2147483648
Or in your case to convert the maxInt int64 value to an int, you could use
for a := 2; a < int(maxInt); a++ {
which would fail to execute correctly if maxInt overflows the max value of the int type on your system.

I came here because of the title, "How to convert an int64 to int in Go?". The answer is,
int(int64Var)

It is correct to use the strconv package
strconv.FormatInt(int64Var, 10)

Related

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

Convert int32 to string in Golang

I need to convert an int32 to string in Golang. Is it possible to convert int32 to string in Golang without converting to int or int64 first?
Itoa needs an int. FormatInt needs an int64.
One line answer is fmt.Sprint(i).
Anyway there are many conversions, even inside standard library function like fmt.Sprint(i), so you have some options (try The Go Playground):
1- You may write your conversion function (Fastest):
func String(n int32) string {
buf := [11]byte{}
pos := len(buf)
i := int64(n)
signed := i < 0
if signed {
i = -i
}
for {
pos--
buf[pos], i = '0'+byte(i%10), i/10
if i == 0 {
if signed {
pos--
buf[pos] = '-'
}
return string(buf[pos:])
}
}
}
2- You may use fmt.Sprint(i) (Slow)
See inside:
// Sprint formats using the default formats for its operands and returns the resulting string.
// Spaces are added between operands when neither is a string.
func Sprint(a ...interface{}) string {
p := newPrinter()
p.doPrint(a)
s := string(p.buf)
p.free()
return s
}
3- You may use strconv.Itoa(int(i)) (Fast)
See inside:
// Itoa is shorthand for FormatInt(int64(i), 10).
func Itoa(i int) string {
return FormatInt(int64(i), 10)
}
4- You may use strconv.FormatInt(int64(i), 10) (Faster)
See inside:
// FormatInt returns the string representation of i in the given base,
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
// for digit values >= 10.
func FormatInt(i int64, base int) string {
_, s := formatBits(nil, uint64(i), base, i < 0, false)
return s
}
Comparison & Benchmark (with 50000000 iterations):
s = String(i) takes: 5.5923198s
s = String2(i) takes: 5.5923199s
s = strconv.FormatInt(int64(i), 10) takes: 5.9133382s
s = strconv.Itoa(int(i)) takes: 5.9763418s
s = fmt.Sprint(i) takes: 13.5697761s
Code:
package main
import (
"fmt"
//"strconv"
"time"
)
func main() {
var s string
i := int32(-2147483648)
t := time.Now()
for j := 0; j < 50000000; j++ {
s = String(i) //5.5923198s
//s = String2(i) //5.5923199s
//s = strconv.FormatInt(int64(i), 10) // 5.9133382s
//s = strconv.Itoa(int(i)) //5.9763418s
//s = fmt.Sprint(i) // 13.5697761s
}
fmt.Println(time.Since(t))
fmt.Println(s)
}
func String(n int32) string {
buf := [11]byte{}
pos := len(buf)
i := int64(n)
signed := i < 0
if signed {
i = -i
}
for {
pos--
buf[pos], i = '0'+byte(i%10), i/10
if i == 0 {
if signed {
pos--
buf[pos] = '-'
}
return string(buf[pos:])
}
}
}
func String2(n int32) string {
buf := [11]byte{}
pos := len(buf)
i, q := int64(n), int64(0)
signed := i < 0
if signed {
i = -i
}
for {
pos--
q = i / 10
buf[pos], i = '0'+byte(i-10*q), q
if i == 0 {
if signed {
pos--
buf[pos] = '-'
}
return string(buf[pos:])
}
}
}
The Sprint function converts a given value to string.
package main
import (
"fmt"
)
func main() {
var sampleInt int32 = 1
sampleString := fmt.Sprint(sampleInt)
fmt.Printf("%+V %+V\n", sampleInt, sampleString)
}
// %!V(int32=+1) %!V(string=1)
See this example.
Use a conversion and strconv.FormatInt to format int32 values as a string. The conversion has zero cost on most platforms.
s := strconv.FormatInt(int64(n), 10)
If you have many calls like this, consider writing a helper function similar to strconv.Itoa:
func formatInt32(n int32) string {
return strconv.FormatInt(int64(n), 10)
}
All of the low-level integer formatting code in the standard library works with int64 values. Any answer to this question using formatting code in the standard library (fmt package included) requires a conversion to int64 somewhere. The only way to avoid the conversion is to write formatting function from scratch, but there's little point in doing that.
func FormatInt32(value int32) string {
return fmt.Sprintf("%d", value)
}
Does this work?

Generate 6-digit Verification Code with Golang?

Generate 6-digit code for phone verification,
The following is a very simple approach that I have used
package main
import (
"fmt"
"math/rand"
"time"
)
var randowCodes = [...]byte{
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
}
func main() {
var r *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < 3; i++ {
var pwd []byte = make([]byte, 6)
for j := 0; j < 6; j++ {
index := r.Int() % len(randowCodes)
pwd[j] = randowCodes[index]
}
fmt.Printf("%s\n", string(pwd))
}
}
Do you have a better way to do this?
You may use "crypto/rand" package: which implements a cryptographically secure pseudorandom number generator. (try on The Go Playground):
package main
import (
"crypto/rand"
"fmt"
"io"
)
func main() {
for i := 0; i < 3; i++ {
fmt.Println(EncodeToString(6))
}
}
func EncodeToString(max int) string {
b := make([]byte, max)
n, err := io.ReadAtLeast(rand.Reader, b, max)
if n != max {
panic(err)
}
for i := 0; i < len(b); i++ {
b[i] = table[int(b[i])%len(table)]
}
return string(b)
}
var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}
output:
640166
195174
221966
And see: How to generate a random string of a fixed length in golang?
I've forked user6169399's answer, using crypto/rand with const string and small modifications, this is the result:
import (
"crypto/rand"
)
const otpChars = "1234567890"
func GenerateOTP(length int) (string, error) {
buffer := make([]byte, length)
_, err := rand.Read(buffer)
if err != nil {
return "", err
}
otpCharsLength := len(otpChars)
for i := 0; i < length; i++ {
buffer[i] = otpChars[int(buffer[i])%otpCharsLength]
}
return string(buffer), nil
}
I think it is the easiest way:
// generate new recovery code
t := fmt.Sprint(time.Now().Nanosecond())
fmt.Println(t[:6])
output:
524339
743142
243470
function use:
func GenerateCode() string {
return fmt.Sprint(time.Now().Nanosecond())[:6]
}
output:
302663
477258
678557
You can use rand.Int() from crypto/rand to also generate randomness
import (
"crypto/rand"
)
func GenerateOTPCode(length int) (string, error) {
seed := "012345679"
byteSlice := make([]byte, length)
for i := 0; i < length; i++ {
max := big.NewInt(int64(len(seed)))
num, err := rand.Int(rand.Reader, max)
if err != nil {
return "", err
}
byteSlice[i] = seed[num.Int64()]
}
return string(byteSlice), nil
}
make use of math/rand:
func genCaptchaCode() string {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
var codes [6]byte
for i := 0; i < 6; i++ {
codes[i] = uint8(48 + r.Intn(10))
}
return string(codes[:])
}
make use of crypto/rand (more security):
func genCaptchaCode() (string, error) {
codes := make([]byte, 6)
if _, err := rand.Read(codes); err != nil {
return "", err
}
for i := 0; i < 6; i++ {
codes[i] = uint8(48 + (codes[i] % 10))
}
return string(codes), nil
}
I needed a bit simpler and flat solution so I came up with this
// Since Go 1.20 rand.Seed() deprecated
rand.New(rand.NewSource(time.Now().UnixNano()))
// generates a random number in the range of [0, 900000)
// We add 100000 to the result to ensure the minimum value is 100000
r := rand.Intn(900000) + 100000
fmt.Println(r)
a side note: rand.Intn(900000) never generates 900000 the max number is 899999 so the code never generates 1,000,000
To account for the observation given by #Tom Anderson, a more appropriate answer using real uniform distribution and a simpler code would be:
func GenerateOTP(maxDigits uint32) string {
bi, err := rand.Int(
rand.Reader,
big.NewInt(int64(math.Pow(10, float64(maxDigits)))),
)
if err != nil {
panic(err)
}
return fmt.Sprintf("%0*d", maxDigits, bi)
}
go playground

Parse number string digits

I am trying to calculate the multiplication result of a few digits which are part of a long digits string. Here is my code:
package main
import (
"fmt"
"strconv"
)
func main() {
inputNum := "73167176531330624919225119"
mult := getMult(3, inputNum)
fmt.Printf("Mult = %d", mult)
}
func getMult(startIndex int, inputNum string) int {
mult := 0
for i := 0; i < 10; i++ {
digit, err := strconv.Atoi(string(inputNum[startIndex+i]))
if err != nil {
mult *= int(digit)
} else {
fmt.Printf("Error converting %s to int : %s\n", string(inputNum[startIndex+i]), err.Error())
}
}
return mult
}
The result I want to get is 6*7*1*7*6*5*3*1*3*3 = 238140
But I an getting a runtime error:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x40130e]
goroutine 1 [running]:
main.getMult(0x3, 0x534d40, 0x1a, 0x4d2701)
test.go:25 +0x17e
main.main()
test.go:10 +0x55
exit status 2
There are a couple problems...
First, you need to start mult at 1, otherwise you will just continually multiply by 0 and always get 0.
Secondly you have the logic for your err check flipped. It should be if err == nil
This seems to do what you want:
func getMult(startIndex int, inputNum string) int {
mult := 1
for i := 0; i < 10; i++ {
digit, err := strconv.Atoi(string(inputNum[startIndex+i]))
if err == nil {
mult *= int(digit)
} else {
fmt.Println(err)
}
}
return mult
}
The error you were getting was because you were trying to print err.Error() when err itself was nil (due to the logical flip of != and ==)
your code will work with fixing these two typos:
change mult := 0 to mult := 1
and change err != nil to err == nil like this:
package main
import (
"fmt"
"strconv"
)
func main() {
inputNum := "73167176531330624919225119"
mult := getMult(3, inputNum)
fmt.Printf("Mult = %d", mult)
}
func getMult(startIndex int, inputNum string) int {
mult := 1
for i := 0; i < 10; i++ {
digit, err := strconv.Atoi(string(inputNum[startIndex+i]))
if err == nil {
mult *= int(digit)
} else {
fmt.Printf("Error converting %s to int : %s\n", string(inputNum[startIndex+i]), err.Error())
}
}
return mult
}
also you may use inputNum[3:13] to get new string from index 3 with length 10,
and you may use int(v - '0') to convert one character to integer number,
then use for range like this:
package main
import "fmt"
func main() {
inputNum := "73167176531330624919225119"
mult := getMult(inputNum[3:13])
fmt.Printf("Mult = %d \n", mult) // Mult = 238140
}
func getMult(str string) int {
m := 1
for _, v := range str {
if v >= '0' && v <= '9' {
m *= int(v - '0')
} else {
fmt.Printf("Error converting %q to int\n", v)
break
}
}
return m
}
output:
Mult = 238140

bytewise compare varint encoded int64's

I'm using levigo, the leveldb bindings for Go. My keys are int64's and need to be kept sorted. By default, leveldb uses a bytewise comparator so I'm trying to use varint encoding.
func i2b(x int64) []byte {
b := make([]byte, binary.MaxVarintLen64)
n := binary.PutVarint(b, x)
return key[:n]
}
My keys are not being sorted correctly. I wrote the following as a test.
var prev int64 = 0
for i := int64(1); i < 1e5; i++ {
if bytes.Compare(i2b(i), i2b(prev)) <= 0 {
log.Fatalf("bytewise: %d > %d", b2i(prev), i)
}
prev = i
}
output: bytewise: 127 > 128
playground
I'm not sure where the problem is. Am I doing the encoding wrong? Is varint not the right encoding to use?
EDIT:
BigEndian fixed width encoding is bytewise comparable
func i2b(x int64) []byte {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(x))
return b
}
The varint encoding is not bytewise comparable* wrt to the order of the values it caries. One option how to write the ordering/collating function (cmp bellow) is for example:
package main
import (
"encoding/binary"
"log"
)
func i2b(x int64) []byte {
var b [binary.MaxVarintLen64]byte
return b[:binary.PutVarint(b[:], x)]
}
func cmp(a, b []byte) int64 {
x, n := binary.Varint(a)
if n < 0 {
log.Fatal(n)
}
y, n := binary.Varint(b)
if n < 0 {
log.Fatal(n)
}
return x - y
}
func main() {
var prev int64 = 0
for i := int64(1); i < 1e5; i++ {
if cmp(i2b(i), i2b(prev)) <= 0 {
log.Fatal("fail")
}
prev = i
}
}
Playground
(*) The reason is (also) the bit fiddling performed.

Resources