Splitting big.Int by digit - go

I'm trying to split a big.Int into a number of int64s such that each is a portion of the larger number, with a standard offset of 18 digits. For example, given the following input value of 1234512351234088800000999, I would expect the following output: [351234088800000999, 1234512]. For negative numbers, I would expect all of the parts to be negative (i.e. -1234512351234088800000999 produces [-351234088800000999, -1234512]).
I already know I can do this to get the result I want:
func Split(input *big.Int) []int64 {
const width = 18
asStr := in.Coefficient().Text(10)
strLen := len(asStr)
offset := 0
if in.IsNegative() {
offset = 1
}
length := int(math.Ceil(float64(strLen-offset) / width))
ints := make([]int64, length)
for i := 1; i <= length; i++ {
start := strLen - (i * width)
end := start + width
if start < 0 || (start == 1 && asStr[0] == '-') {
start = 0
}
ints[i-1], _ = strconv.ParseInt(asStr[start:end], 10, 64)
if offset == 1 && ints[i-1] > 0 {
ints[i-1] = 0 - ints[i-1]
}
}
return ints
}
However, I don't like the idea of using string-parsing nor do I like the use of strconv. Is there a way I can do this utilizing the big.Int directly?

You can use the DivMod function to do what you need here, with some special care to handle negative numbers:
var offset = big.NewInt(1e18)
func Split(input *big.Int) []int64 {
rest := new(big.Int)
rest.Abs(input)
var ints []int64
r := new(big.Int)
for {
rest.DivMod(rest, offset, r)
ints = append(ints, r.Int64() * int64(input.Sign()))
if rest.BitLen() == 0 {
break
}
}
return ints
}
Multiplying each output by input.Sign() ensures that each output will be negative if the input is negative. The sum of the output values multiplied by 1e18 times their position in the output should equal the input.

Related

how to simplimize my go script because always get time out in hackerrank

I have a test interview as a Go Developer and have to do some of the tasks on hackerrank.
I've done the task, but when I submit my script it always "times out".. maybe because there are a lot of loops that I use to do this function, and the task is :
So, my solution are :
Loop from a to b with a increment.
Define the digit sum with modulus by 10, sum the result with the leftover.
Define the square sum with converting int(a) to string then use for-range to sum the values.
checking if digit sum and square sum is a prime number, if so then count++
My script is :
func main() {
fmt.Printf("Jadi ada %d bilangan prima \n", luckyNumbers(1, 20))
}
func luckyNumbers(a int64, b int64) int64 {
count := 0
for min, max := a, b; min <= max; min++ {
squareSum := digitSquare(min)
digitSum := digitSum(min)
if isPrime(digitSum) && isPrime(squareSum) {
count++
}
}
return int64(count)
}
func digitSquare(number int64) int64 {
numStr := strconv.Itoa(int(number))
var firstDigit, secondDigit int
for _, digit := range numStr {
numInt, _ := strconv.Atoi(string(digit))
pow := int(math.Pow(float64(numInt), 2))
if firstDigit == 0 {
firstDigit += pow
} else {
secondDigit += pow
}
}
squareSum := int64(firstDigit + secondDigit)
return squareSum
}
func digitSum(number int64) int64 {
var remainder, sumResult int64 = 0, 0
for number != 0 {
remainder = number % 10
sumResult += remainder
number /= 10
}
return sumResult
}
func isPrime(num int64) bool {
if num < 2 {
return false
}
for i := int64(2); i <= int64(math.Sqrt(float64(num))); i++ {
if num%i == 0 {
return false
}
}
return true
}
The script above is the best script that I can make right now, I understand that I do a lot of iterations, so when I try to submit it will always show "time out". So I want to learn from you and want to see if there is a simpler script so that it can be submitted.
Thank you,
Regards

Why is is leetcode saying my atoi answer is incorrect? Is it acutally incorrect? Or is there a bug in leetcode

I am doing the atoi problem in leetcode and I submitted my code below which isn't too important. I am wondering if it is a valid failure leetcode gave me. It seems like my code is doing the right thing.
Here is the problem description:
Here is the code:
const (
MaxInt32 = 1<<31 - 1
MinInt32 = -1 << 31
)
func myAtoi(str string) int {
if len(str) < 1 {
return 0
}
// count to keep track of the number of digits
count := 0
// container for digits
values := make([]rune, 0)
// constant we are going to need
minus := "-"
plus := "+"
lastWasPrefix := false
// is the number negative or lead with dash
negative := false
clean := strings.TrimSpace(str)
for _, char := range clean {
isNumber := unicode.IsNumber(char)
isMinus := string(char) == minus
isPlus := string(char) == plus
isPrefix := isMinus || isPlus
// checking for two prefixes following eachother
if isPrefix && lastWasPrefix {
return 0
}
if isPrefix {
lastWasPrefix = true
}
curLen := len(values)
if !isNumber && !isPrefix && curLen == 0 {
return 0
}
if !isNumber && !isPrefix && curLen != 0 {
break
}
if isMinus {
negative = true
continue
}
if isNumber {
// add value in order and inc. count
values = append(values, char)
count++
}
}
postLen := len(values)
if postLen == 0 {
return 0
}
multiplier := int32(1)
ten := int32(10)
total := int32(0)
for i := postLen - 1; i >= 0; i-- {
diff := MaxInt32 - total
added := CharToNum(values[i]) * multiplier
// added will be zero if we overflow the int
if added > diff || added < 0 {
return MinInt32
}
total += added
multiplier *= ten
}
if negative {
return int(total * int32(-1))
} else {
return int(total)
}
}
/**
a rune is a uni code char so we need to conver from unicode int to digit
*/
func CharToNum(r rune) (int32) {
for i := 48; i <= 57; i++ {
if int(r) == i {
return int32(r) - 48
}
}
return -1
}
Any help understanding this error would be much appreciated. I don't want any help with the algorithm. Is this a valid error or not?
Without checking your algorithm I can see the following in the error message:
The maximum 32bit int value is 2,147,483,647 which is expected to be returned when you get a string representing a larger value than that (e.g. your input was "2147483648" which is larger by one). Your program apparently returns -2147483648.
The specification is ambiguous "if the numerical value is out of the range of representable values INT_MAX or INT_MIN is retuned". The authors had in mind to return the value matching in sign but this is not clearly stated.
So I would say when you return INT_MIN for a number that is larger than INT_MAX this could be considered correct (although it is somewhat illogical).

How to improve my function that rounds floats to nearest 10 if 2 digit number, 100 if 3 digit number etc

I am drawing bar charts and i've come across a tricky problem. How to programmatically set the max value for the y axis label depending on the max value for a given series. So if you had a bar with a value of 7, you might want the y axis to go up to 10
My approach is not ideal but works like this:
Get a number to round, like 829
Count the number of digits (3)
Use a loop to convert to a string of 0s ("000")
Add a 1 to the start of the string then convert to a float (1000)
Find the difference (1000 - 829 = 171)
Get the first digit of the difference (1) and then add that to the first digit of the float, with the remaining set to zero ("900"), then convert to a number (900)
This means that 725 will see a y axis max label number of 800, and 829 of 900
My code works, but I feel like it's a piece of crap with a hacky approach
I have to code for big numbers. For example, if the float I want to find the max value for is >10000 then take the first two digits, and add 1000 to it. If >100,000 add 10,000
How can I improve here? I'm a little stuck, is my idea of converting to strings even right?!
Full code here:
package main
import (
"fmt"
"strconv"
)
func main() {
myFloat := 899175.0
x := getMaxYAxisValueForChart(myFloat)
fmt.Println("The number to find the maximum value for is: ", myFloat)
fmt.Println("This should be the max value for the y axis: ", x)
}
func getMaxYAxisValueForChart(float float64) (YAxisMaximum float64) {
//Convert to string with no decimals
floatAsString := fmt.Sprintf("%.f", float)
//Get length of the string float
floatAsStringLength := len(floatAsString)
//For each digit in the string, make a zero-string
stringPowerTen := "0"
for i := 1; i < floatAsStringLength; i++ {
stringPowerTen += "0"
}
//Add a 1 to the 0 string to get the difference from the float
stringPowerTenWithOne := "1" + stringPowerTen
//Convert the number string to a float
convertStringPowerTenToFloat := ConvertStringsToFloat(stringPowerTenWithOne)
//Get the difference from the denominator from the numerator
difference := convertStringPowerTenToFloat - float
//We want to isolate the first digit to check how far the float is (100 is far from 1000) and then correct if so
floatAsStringDifference := fmt.Sprintf("%.f", difference)
runes := []rune(floatAsStringDifference)
floatAsStringDifferenceFirstDigit := string(runes[0])
//For the denominator we want to take away the difference that is rounded to the nearest ten, hundred etc
runes = []rune(stringPowerTen)
differenceLastDigitsAsString := ""
if difference < 10 {
differenceLastDigitsAsString = "1"
} else if difference < 30 && difference < 100 {
differenceLastDigitsAsString = "0"
} else {
differenceLastDigitsAsString = floatAsStringDifferenceFirstDigit + string(runes[1:])
}
//Convert the number difference string from total to a float
convertDifferenceStringPowerTenToFloat := ConvertStringsToFloat(differenceLastDigitsAsString)
YAxisMaximum = convertStringPowerTenToFloat - convertDifferenceStringPowerTenToFloat
//If float is less than 10,0000
if float < 10000 && (YAxisMaximum-float >= 500) {
YAxisMaximum = YAxisMaximum - 500
}
if float < 10000 && (YAxisMaximum-float < 500) {
YAxisMaximum = YAxisMaximum
}
//If number bigger than 10,000 then get the nearest 1,000
if float > 10000 {
runes = []rune(floatAsString)
floatAsString = string(runes[0:2])
runes = []rune(stringPowerTen)
stringPowerTen = string(runes[2:])
runes = []rune(stringPowerTenWithOne)
stringPowerTenWithOne = string(runes[0:(len(stringPowerTenWithOne) - 2)])
YAxisMaximum = ConvertStringsToFloat(floatAsString+stringPowerTen) + ConvertStringsToFloat(stringPowerTenWithOne)
}
if float > 10000 {
runes = []rune(floatAsString)
floatAsString = string(runes[0:2])
runes = []rune(stringPowerTen)
stringPowerTen = string(runes[:])
runes = []rune(stringPowerTenWithOne)
stringPowerTenWithOne = string(runes[0:(len(stringPowerTenWithOne))])
YAxisMaximum = ConvertStringsToFloat(floatAsString+stringPowerTen) + ConvertStringsToFloat(stringPowerTenWithOne)
}
return YAxisMaximum
}
func ConvertStringsToFloat(stringToConvert string) (floatOutput float64) {
floatOutput, Error := strconv.ParseFloat(stringToConvert, 64)
if Error != nil {
fmt.Println(Error)
}
return floatOutput
}
Here is the solution based off of Matt Timmermans answer, but converted to work in Go:
func testing(float float64) (YAxisMaximum float64) {
place := 1.0
for float >= place*10.0 {
place *= 10.0
}
return math.Ceil(float/place) * place
}
Wow, that's a pretty complicated procedure you have. This is how I would do it if the numbers aren't enormous. I don't know go, so I'm going to guess about how to write it in that language:
func getMaxYAxisValueForChart(float float64) {
place := 1.0;
while float >= place*10.0 {
place *= 10.0;
}
return math.Ceil(float/place) * place;
}
You can get the magnitude of a number using Math.Log10
int magnitude = (int)Math.Pow(10, (int)Math.Log10(value));
Use that to divide the number down, calculate ceiling and then scale it back up.
No strings, no while loops.
Take the length of the string and calculate that 10 to the power of that length
Or...better take the Log base 10, get the integer part, add 1 and then return that to the power of 10 :)
import (
"fmt"
"math"
)
//func PowerScale(x int) int64{
// return int64(math.Pow(10,float64(len((fmt.Sprintf("%d",x))))))
//}
func PowerScale(x int) int64 {
return int64(math.Pow(10,float64(int(math.Log10(float64(x))+1))))
}
func main() {
fmt.Println(PowerScale(829))
fmt.Println(PowerScale(7))
}
Since 829 is an int, or can be cast to, a pure integer solution :
func getMaxYAxisValueForChart(int int64) {
base := 10;
while int > base*10 {
base := 10 * base;
}
return int + (base - int) % base;
}

Too many results in a loop for Project Euler #145

I am trying to create a solution for Project Euler #145. I am writing in Go. When I run my program I get a result of 125. The expected result is 120. I have 2 different ways I have tried to write the code but both come up with the same answer. Any help pointing out my error would be appreciated.
Code option #1 using strings:
package main
import (
"fmt"
"strconv"
)
//checks to see if all the digits in the number are odd
func is_Odd(sum int) bool {
intString := strconv.Itoa(sum)
for x := len(intString); x > 0; x-- {
newString := intString[x-1]
if newString%2 == 0 {
return false
}
}
return true
}
//reverse the number passed
func reverse_int(value int) int {
intString := strconv.Itoa(value)
newString := ""
for x := len(intString); x > 0; x-- {
newString += string(intString[x-1])
}
newInt, err := strconv.Atoi(newString)
if err != nil {
fmt.Println("Error converting string to int")
}
return newInt
}
//adds 2 int's passed to it and returns an int
func add(x int, y int) int {
return x + y
}
func main() {
//functions test code
/*y := 35
x := reverse_int(y)
z := add(x,y)
fmt.Println(is_Odd(z))*/
counter := 1
for i := 1; i < 1000; i++ {
flipped := reverse_int(i)
sum := add(flipped, i)
oddCheck := is_Odd(sum)
if oddCheck {
fmt.Println(counter, ":", i, "+", flipped, "=", sum)
counter++
}
}
counter--
fmt.Println("total = ", counter)
}
Code option #2 using only ints:
package main
import (
"fmt"
)
var counter int
//breaks down an int number by number and checks to see if
//all the numbers in the int are odd
func is_Odd(n int) bool {
for n > 0 {
remainder := n % 10
if remainder%2 == 0 {
return false
}
n /= 10
}
return true
}
//adds 2 int's passed to it and returns an int
func add(x int, y int) int {
return x + y
}
//reverses the int passed to it and returns an int
func reverse_int(n int) int {
var new_int int
for n > 0 {
remainder := n % 10
new_int *= 10
new_int += remainder
n /= 10
}
return new_int
}
func main() {
//functions test code
/*y := 35
x := reverse_int(y)
z := add(x,y)
fmt.Println(is_Odd(z))*/
counter = 1
for i := 1; i < 1000; i++ {
flipped := reverse_int(i)
sum := add(flipped, i)
oddCheck := is_Odd(sum)
if oddCheck {
//fmt.Println(counter,":",i,"+",flipped,"=",sum)
counter++
}
}
counter--
fmt.Println(counter)
}
Leading zeroes are not allowed in either n or reverse(n) so in reverse(n int) int remove Leading zeroes like so:
remainder := n % 10
if first {
if remainder == 0 {
return 0
}
first = false
}
try this:
package main
import (
"fmt"
)
//breaks down an int number by number and checks to see if
//all the numbers in the int are odd
func isOdd(n int) bool {
if n <= 0 {
return false
}
for n > 0 {
remainder := n % 10
if remainder%2 == 0 {
return false
}
n /= 10
}
return true
}
//adds 2 int's passed to it and returns an int
func add(x int, y int) int {
return x + y
}
//reverses the int passed to it and returns an int
func reverse(n int) int {
first := true
t := 0
for n > 0 {
remainder := n % 10
if first {
if remainder == 0 {
return 0
}
first = false
}
t *= 10
t += remainder
n /= 10
}
return t
}
func main() {
counter := 0
for i := 0; i < 1000; i++ {
flipped := reverse(i)
if flipped == 0 {
continue
}
sum := add(flipped, i)
if isOdd(sum) {
counter++
//fmt.Println(counter, ":", i, "+", flipped, "=", sum)
}
}
fmt.Println(counter)
}
output:
120
You're ignoring this part of the criteria:
Leading zeroes are not allowed in either n or reverse(n).
Five of the numbers you count as reversible end in 0. (That means their reverse has a leading zero.) Stop counting those as reversible and you're done.
Some positive integers n have the property that the sum [ n +
reverse(n) ] consists entirely of odd (decimal) digits. For instance,
36 + 63 = 99 and 409 + 904 = 1313. We will call such numbers
reversible; so 36, 63, 409, and 904 are reversible. Leading zeroes are
not allowed in either n or reverse(n).
All digits of the sum must all be odd.
Try this one: https://play.golang.org/p/aUlvKrb9SB

Convert rune to int?

In the following code, I iterate over a string rune by rune, but I'll actually need an int to perform some checksum calculation. Do I really need to encode the rune into a []byte, then convert it to a string and then use Atoi to get an int out of the rune? Is this the idiomatic way to do it?
// The string `s` only contains digits.
var factor int
for i, c := range s[:12] {
if i % 2 == 0 {
factor = 1
} else {
factor = 3
}
buf := make([]byte, 1)
_ = utf8.EncodeRune(buf, c)
value, _ := strconv.Atoi(string(buf))
sum += value * factor
}
On the playground: http://play.golang.org/p/noWDYjn5rJ
The problem is simpler than it looks. You convert a rune value to an int value with int(r). But your code implies you want the integer value out of the ASCII (or UTF-8) representation of the digit, which you can trivially get with r - '0' as a rune, or int(r - '0') as an int. Be aware that out-of-range runes will corrupt that logic.
For example, sum += (int(c) - '0') * factor,
package main
import (
"fmt"
"strconv"
"unicode/utf8"
)
func main() {
s := "9780486653556"
var factor, sum1, sum2 int
for i, c := range s[:12] {
if i%2 == 0 {
factor = 1
} else {
factor = 3
}
buf := make([]byte, 1)
_ = utf8.EncodeRune(buf, c)
value, _ := strconv.Atoi(string(buf))
sum1 += value * factor
sum2 += (int(c) - '0') * factor
}
fmt.Println(sum1, sum2)
}
Output:
124 124
why don't you do only "string(rune)".
s:="12345678910"
var factor,sum int
for i,x:=range s{
if i%2==0{
factor=1
}else{
factor=3
}
xstr:=string(x) //x is rune converted to string
xint,_:=strconv.Atoi(xstr)
sum+=xint*factor
}
fmt.Println(sum)
val, _ := strconv.Atoi(string(v))
Where v is a rune
More concise but same idea as above

Resources