The problem that Precision loss in big.Float - go

While running:
package main
import (
"fmt"
"math/big"
)
func main() {
a := big.NewFloat(float64(2.1234))
fmt.Println(a.Text(102,18))
}
I expected 2.123400000000000000 as output, but instead got 2.123400000000000176.
Can someone explain me why I do not have the expected number?

big.NewFloat(float64(2.1234))
float64(2.1234) converts to Go float64 (IEEE-754 64-bit floating-point), which has 53 bits of precision.
For example,
package main
import (
"fmt"
"math/big"
)
func main() {
// 53 bits of precision (float64)
a := big.NewFloat(float64(2.1234))
fmt.Println(a.Text(102, 18))
x := "2.1234"
// 53 bits of precision
f, _, err := big.ParseFloat(x, 10, 53, big.ToNearestEven)
if err != nil {
panic(err)
}
fmt.Println(f.Text(102, 18))
// 256 bits of precision
f, _, err = big.ParseFloat(x, 10, 256, big.ToNearestEven)
if err != nil {
panic(err)
}
fmt.Println(f.Text(102, 18))
}
Playground: https://play.golang.org/p/z5iK90lQcD9
Output:
2.123400000000000176
2.123400000000000176
2.123400000000000000

Related

Go Test Input and Output from File

was trying to determine if there's a way to take a given input and expected output from a file for use in go test.
main.go:
package main
import (
"fmt"
"math"
)
func main() {
var n, m, a float64
fmt.Scanln(&n, &m, &a)
a_in_n_ceil := uint64(math.Ceil(n / a))
a_in_m_ceil := uint64(math.Ceil(m / a))
a_in_n_and_m := a_in_n_ceil * a_in_m_ceil
fmt.Println(a_in_n_and_m)
}
examples:
6 6 4
4
Would it be io.readfile or something similar to grab the first line of input from the examples file and then again for the seconds line of expected output in main_test.go? Guidance is appreciated.
Use os package for file read & write
To read from file : os.ReadFile(path_to_file)
To write file : os.WriteFile("output.txt", data_in_byte_array, file_permission)
package main
import (
"fmt"
"math"
"os"
"strconv"
"strings"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func ReadFromFile(path string) []float64 {
dat, err := os.ReadFile(path) // read file contents
check(err)
stringArr := strings.Split(string(dat)," ")
var numbers []float64
for _, arg := range stringArr {
if n, err := strconv.ParseFloat(arg, 64); err == nil {
numbers = append(numbers, n)
}
}
return numbers // return file contents in required format (in this case []float64)
}
func WriteFile(data string) error{
err := os.WriteFile("output.txt", []byte(data), 0644)
if err != nil {
return err
}
return nil
}
func main(){
var n, m, a float64
numbers := ReadFromFile("input.txt")
fmt.Println(numbers)
n = numbers[0]
m = numbers[1]
a = numbers[2]
a_in_n_ceil := uint64(math.Ceil(n / a))
a_in_m_ceil := uint64(math.Ceil(m / a))
a_in_n_and_m := a_in_n_ceil * a_in_m_ceil
fmt.Println(a_in_n_and_m) // print to console
err = WriteFile(fmt.Sprint(a_in_n_and_m)) // write output to a file
if err != nil {
fmt.Println("Error in file write : ", err)
}
}
input.txt
6 6 4
output.txt
4

golang calculate full precision float number

Used a decimal point of 200 as the precision, I need to calculate a number from atto to decimal number similar screenshot.
To get the values at precision of nano and atto you can use %.9f and %.18f in fmt.Printf() respectively,I created a small program to get your value of 0.000000000000099707 as follows:
package main
import (
"fmt"
"math"
)
func main() {
powr := math.Pow(10, -18)
numb := 99707 * powr
fmt.Println("number", numb)
fmt.Printf("\nthe value in atto %.18f\n", numb)
}
Output:
number 9.970700000000001e-14
the value in atto 0.000000000000099707
You can use the github.com/shopspring/decimal package for this as well. This library can represents numbers up to 2^31 (2147483648) digits. Here is a simple code to do the calculation:
d := decimal.NewFromInt(99707)
d10 := decimal.NewFromInt(10)
dpow := decimal.NewFromInt(-18)
d10pow := d10.Pow(dpow)
dmul := d.Mul(d10pow)
fmt.Println(dmul)
This can simplified to:
d := decimal.NewFromInt(99707).Mul(decimal.NewFromInt(10).Pow(decimal.NewFromInt(-18)))
fmt.Println(d)
Output: 0.000000000000099707
See playground
I was interested in how to do this so I found the apd package from cockroach that handles arbitrary precision calculations. You can use it like this:
import (
"fmt"
"github.com/cockroachdb/apd"
)
func main() {
// 99707 * 10^(-18)
n1 := apd.New(99707, 0)
n2 := apd.New(10, 0)
n3 := apd.New(-18, 0)
c := apd.BaseContext.WithPrecision(200)
res := apd.New(0,0)
ctx, err := c.Pow(res, n2, n3)
if err != nil {
panic(err)
}
ctx, err = c.Mul(res, res, n1)
if err != nil {
panic(err)
}
fmt.Println(ctx.Inexact(), res.Text('f'))
}
And it will output:
false 0.000000000000099707
You will have to be careful with the loss of precision that may happen and look at the inexact field.

Reading a user input and splitting it into two float64 numbers

I have a function to read a single float64 from stdin:
func readFloat() float64 {
scanner := bufio.NewScanner(os.Stdin)
for {
scanner.Scan()
in := scanner.Text()
n, err := strconv.ParseFloat(in, 64)
if err == nil {
return n
} else {
fmt.Println("ERROR:", err)
fmt.Print("\nPlease enter a valid number: ")
}
}
}
I would like to modify this to read two floating point numbers for e.g.
func main() {
fmt.Print("\nEnter x, y coordinates for point1: ")
x1, y1 := readFloat()
Problem I am facing is splitting scanner.Text(). There is a function scanner.Split() but cannot understand how to use it.
Any possible solutions would be helpful.
I would probably go with fmt.Sscanf here
package main
import (
"fmt"
)
func main() {
testCases := []string{"1,2", "0.1,0.2", "1.234,2.234"}
var a, b float64
for _, s := range testCases {
_, err := fmt.Sscanf(s, "%f,%f", &a, &b)
if err != nil {
panic(err)
}
fmt.Printf("Got %f, %f\n", a, b)
}
}
output:
Got 1.000000, 2.000000
Got 0.100000, 0.200000
Got 1.234000, 2.234000
https://play.golang.org/p/7ATyjlkPhnD
Use strings.Split:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func readFloat() (float64, float64) {
scanner := bufio.NewScanner(os.Stdin)
for {
scanner.Scan()
in := scanner.Text()
parts := strings.Split(in, ",")
x, err := strconv.ParseFloat(parts[0], 64)
if err != nil {
fmt.Println("ERROR:", err)
fmt.Print("\nPlease enter a valid number: ")
}
y, err := strconv.ParseFloat(parts[1], 64)
if err != nil {
fmt.Println("ERROR:", err)
fmt.Print("\nPlease enter a valid number: ")
}
return x, y
}
}
func main() {
fmt.Print("\nEnter x, y coordinates for point1: ")
x1, y1 := readFloat()
fmt.Println(x1, y1)
}
Using it:
$ go run main.go
Enter x, y coordinates for point1: 1.2,3.4
1.2 3.4

Using big integer values in Go? (ParseInt only converts up to "2147483647"?)

How do you convert a long string of digits (50 digits) into an integer in Go?
I am getting the output for the code below:
number = 2147483647
err = strconv.ParseInt: parsing "37107287533902102798797998220837590246510135740250
": value out of range
It seems to be able to convert numbers only up to 2147483647.
package main
import "fmt"
import "io/ioutil"
import "strings"
import "strconv"
var (
number int64
)
func main() {
fData,err := ioutil.ReadFile("one-hundred_50.txt")
if err != nil {
fmt.Println("Err is ",err)
}
strbuffer := string(fData)
lines := strings.Split(strbuffer, "\n")
for i, line := range lines {
fmt.Printf("%d: %s\n", i, line)
number, err := strconv.Atoi(line)
fmt.Println("number = ", number)
fmt.Println("err = ", err)
}
}
You want the math/big package, which provides arbitrary-precision integer support.
import "math/big"
func main() {
// ...
for i, line := range lines {
bi := big.NewInt(0)
if _, ok := bi.SetString(line, 10); ok {
fmt.Printf("number = %v\n", bi)
} else {
fmt.Printf("couldn't interpret line %#v\n", line)
}
}
}
Here's a quick example of it working.

Reading an integer from standard input

How do I use the fmt.Scanf function in Go to get an integer input from the standard input?
If this can't be done using fmt.Scanf, what's the best way to read a single integer?
http://golang.org/pkg/fmt/#Scanf
All the included libraries in Go are well documented.
That being said, I believe
func main() {
var i int
_, err := fmt.Scanf("%d", &i)
}
does the trick
An alternative that can be a bit more concise is to just use fmt.Scan:
package main
import "fmt"
func main() {
var i int
fmt.Scan(&i)
fmt.Println("read number", i, "from stdin")
}
This uses reflection on the type of the argument to discover how the input should be parsed.
http://golang.org/pkg/fmt/#Scan
Here is my "Fast IO" method for reading positive integers. It could be improved with bitshifts and laying out memory in advance.
package main
import (
"io/ioutil"
"bufio"
"os"
"strconv"
)
func main() {
out := bufio.NewWriter(os.Stdout)
ints := getInts()
var T int64
T, ints = ints[0], ints[1:]
..
out.WriteString(strconv.Itoa(my_num) + "\n")
out.Flush()
}
}
func getInts() []int64 {
//assumes POSITIVE INTEGERS. Check v for '-' if you have negative.
var buf []byte
buf, _ = ioutil.ReadAll(os.Stdin)
var ints []int64
num := int64(0)
found := false
for _, v := range buf {
if '0' <= v && v <= '9' {
num = 10*num + int64(v - '0') //could use bitshifting here.
found = true
} else if found {
ints = append(ints, num)
found = false
num = 0
}
}
if found {
ints = append(ints, num)
found = false
num = 0
}
return ints
}
Golang fmt.Scan is simpler than Golang fmt.Scanf (which is simpler than Clang scanf)
If fmt.Scan errors i.e. if not nil, log & return
1 Read single variable:
import (
"fmt"
"log"
)
var i int
if _, err := fmt.Scan(&i); err != nil {
log.Print(" Scan for i failed, due to ", err)
return
}
fmt.Println(i)
2 Read multiple variables:
import (
"fmt"
"log"
)
var i, j, k int
if _, err := fmt.Scan(&i, &j, &k); err != nil {
log.Print(" Scan for i, j & k failed, due to ", err)
return
}
fmt.Println(i, j, k)
Best of luck
Example from: http://www.sortedinf.com/?q=golang-in-1-hour
You can use fmt.Scanf with a format specifier. The format specifier for the integer is %d. So you can use standard input like below.
func main() {
var someVar int
fmt.Scanf("%d", &someVar)
}
or else you can use fmt.Scan or fmt.Scanln as below.
func main() {
var someVar int
fmt.Scanln(&someVar)
}
You could also use bufio.NewReader to read an integer from the standard input.
The below program:
Prompts for an integer input
Creates a bufio.Reader to read from standard input
Reads input till it encounters a newline character '\n' (Note that this will only read a single integer. Space separated values will not work)
Removes the newline character
Converts string to int
package main
import (
"fmt"
"bufio"
"os"
"strconv"
"strings"
)
func getInt() error {
fmt.Println("Enter an integer")
userInput := bufio.NewReader(os.Stdin)
userVal, err := userInput.ReadString('\n')
if err != nil {
return err
}
input := strings.TrimSpace(userVal)
intVal, err := strconv.Atoi(input)
if err != nil {
return err
}
fmt.Printf("You entered: %d\n", intVal)
return nil
}
func main() {
getInt()
}
Why can't we just use a scanf? just like we use in C? it's working though.
package main
import "fmt"
func main() {
var i int
fmt.Scanf("%d", &i)
fmt.Println(i)
}

Resources