How to read float notation in golang? - go

When printing out some values from a map of structs. I see certain float64 values with alternative notation. The test passes but how do you read this notation (4e-06). Is this value indeed the same as "0.000004"?
package main
import (
"fmt"
"strconv"
"testing"
)
func TestXxx(t *testing.T) {
num := fmt.Sprintf("%f", float64(1.225788)-float64(1.225784)) // 0.000004
f, _ := strconv.ParseFloat(num, 64)
if f == 0.000004 {
t.Log("Success")
} else {
t.Error("Not Equal", num)
}
if getFloat(f) == 0.000004 {
t.Log("Success")
}else{
t.Error("Fail", getFloat(f))
}
}
func getFloat(f float64) float64 {
fmt.Println("My Float:",f) // 4e-06
return f
}

The notation is called Scientific notation, and it is a convenient way to print very small or very large numbers in compact, short form.
It has the form of
m × 10n
(m times ten raised to the power of n)
In programming languages it is written / printed as:
men
See Spec: Floating-point literals.
Your number: 4e-06, where m=4 and n=-6, which means 4*10-6 which equals to 0.000004.

In order to print your floats in a regular way you can do something like this example:
package main
import (
"fmt"
"strconv"
)
func main() {
a, _ := strconv.ParseFloat("0.000004", 64)
b, _ := strconv.ParseFloat("0.0000000004", 64)
c := fmt.Sprintf("10.0004")
cc, _ := strconv.ParseFloat(c, 64)
fmt.Printf("%.6f\n", a) // 6 numbers after the point
fmt.Printf("%.10f\n", b) // 10 numbers afer the point
fmt.Printf("%.4f\n", cc) // 4 numbers after the point
}
Output:
0.000004
0.0000000004
10.0004

It is the same number. You can use fmt.Printf("My Float: %.6f\n",f) if you don't like the scientific notation. (This format requests that 6 digits will be printed after the decimal point.)

Related

Split a string of one side letters, one side numbers

I’m having a mind blank on this one. I am receiving strings of the format..
AB1234
ABC1234
ABC123
AB12
etc etc. Essentially, flight numbers
They could have one or two letters and anything from 1 to 5 numbers. I want to split the string so that I end up with two strings, one with the numbers and one with the letters.
Any ideas? I’ve looked through these but can’t see one that would do the job
https://www.dotnetperls.com/split-go
Update:
Just found and will use this unless there’s a better option. Delete all letters / numbers to create the strings needed https://golangcode.com/how-to-remove-all-non-alphanumerical-characters-from-a-string/
You could take advantage of the fact that Go is a programming language and write a simple Go function. For example,
package main
import (
"fmt"
)
func parseFlight(s string) (letters, numbers string) {
var l, n []rune
for _, r := range s {
switch {
case r >= 'A' && r <= 'Z':
l = append(l, r)
case r >= 'a' && r <= 'z':
l = append(l, r)
case r >= '0' && r <= '9':
n = append(n, r)
}
}
return string(l), string(n)
}
func main() {
flights := []string{"AB1234", "ABC1234", "ABC123", "AB12"}
for _, flight := range flights {
letters, numbers := parseFlight(flight)
fmt.Printf("%q: %q %q\n", flight, letters, numbers)
}
}
Playground: https://play.golang.org/p/pDrsqntAP6E
Output:
"AB1234": "AB" "1234"
"ABC1234": "ABC" "1234"
"ABC123": "ABC" "123"
"AB12": "AB" "12"
It looks like Go's regex syntax does not support lookahead, so you will have to match the two parts and extract them manually, rather than using a split method.
package main
import (
"regexp"
"fmt"
)
var reFlightNumbers = regexp.MustCompile("([A-Z]+)([0-9]+)")
func main() {
matches := reFlightNumbers.FindStringSubmatch("ABC123")
fmt.Println(matches[1])
fmt.Println(matches[2])
}
You can use strings.IndexAny:
package flight
import "strings"
func split(s string) (string, string) {
n := strings.IndexAny(s, "0123456789")
return s[:n], s[n:]
}
or strings.IndexFunc:
package flight
import (
"strings"
"unicode"
)
func split(s string) (string, string) {
n := strings.IndexFunc(s, unicode.IsDigit)
return s[:n], s[n:]
}
https://golang.org/pkg/strings#IndexAny
https://golang.org/pkg/strings#IndexFunc

Cannot round to nearest .0001

I have the following:
package main
import (
"fmt"
"math"
)
func main() {
nums := []float64{
0.15807659924030304, 0.10901273787021637, 0.04955724626779556, 0.05886702239513397,
}
for _, f := range nums {
fmt.Println(f, math.Round(f/.0001)*.0001)
}
}
output is:
0.15807659924030304 0.15810000000000002
0.10901273787021637 0.109
0.04955724626779556 0.049600000000000005
0.05886702239513397 0.0589
Why are some ending up with > 4 decimal places? How do I correct it?
https://play.golang.org/p/kLvVjmsjq6Y
fmt.Printf("%f %b %0.4f\n", f, f, math.Round(f/.0001)*.0001)
Try using that. The %0.4f will format it to 4 decimal places. In fact if you only need the string, use that instead of your Round function.
The %b will show you the real value. In Go that will display a large decimal (base-10) value, a p, then the exponent in powers of 2. So when it displays 5695309707476992p-55 you can find the floating point by doing 5695309707476992 / 2^55

Two's complement and fmt.Printf

So computers use Two's complement to internally represent signed integers. I.e., -5 is represented as ^5 + 1 = "1111 1011".
However, trying to print the binary representation, e.g. the following code:
var i int8 = -5
fmt.Printf("%b", i)
Outputs -101. Not quite what I'd expect. Is the formatting different or is it not using Two's complement after all?
Interestingly, converting to an unsigned int results in the "correct" bit pattern:
var u uint8 = uint(i)
fmt.Printf("%b", u)
Output is 11111011 - exactly the 2s complement of -5.
So it seems to me the value is internally the really using Two's complement, but the formatting is printing the unsigned 5 and prepending a -.
Can somebody clarify this?
I believe the answer lies in how the fmt module formats binary numbers, rather than the internal format.
If you take a look at fmt.integer, one of the very first actions that the function does is to convert the negative signed integer to a positive one:
165 negative := signedness == signed && a < 0
166 if negative {
167 a = -a
168 }
There's then logic to append - in front of the string that's output here.
IOW -101 really is - appended to 5 in binary.
Note: fmt.integer is called from pp.fmtInt64 in print.go, itself called from pp.printArg in the same function.
Here is a method without using unsafe:
package main
import (
"fmt"
"math/bits"
)
func unsigned8(x uint8) []byte {
b := make([]byte, 8)
for i := range b {
if bits.LeadingZeros8(x) == 0 {
b[i] = 1
}
x = bits.RotateLeft8(x, 1)
}
return b
}
func signed8(x int8) []byte {
return unsigned8(uint8(x))
}
func main() {
b := signed8(-5)
fmt.Println(b) // [1 1 1 1 1 0 1 1]
}
In this case you could also use [8]byte, but the above is better if you have
a positive integer, and want to trim the leading zeros.
https://golang.org/pkg/math/bits#RotateLeft
Unsafe pointers must be used to correctly represent negative numbers in binary format.
package main
import (
"fmt"
"strconv"
"unsafe"
)
func bInt8(n int8) string {
return strconv.FormatUint(uint64(*(*uint8)(unsafe.Pointer(&n))), 2)
}
func main() {
fmt.Println(bInt8(-5))
}
Output
11111011

How do I convert a float64 (stored as base-2) to a coefficient and exponent in base-10?

I'm looking for an algorithm that takes a 64-bit floating point number and outputs an exponent and coefficient so the input can be represented in the form float64 input = coefficient * 10 ^ exponent.
Supposedly this is 'not trivial', and many implementations of accurate decimal formats for Golang (which doesn't have a built-in decimal type) have some kind of hack for it like converting to a string and parsing that. While that solution does work in the packages I've seen, it just seems 'proper' to do it the mathematical/computer science-y way.
It may be not 100% precise, but you can use Log10:
package main
import (
"fmt"
"math"
)
func parts(v float64) (float64, int) {
e := math.Floor(math.Log10(v))
c := v / math.Pow(10, e)
return c, int(e)
}
func main() {
c, e := parts(1348.234e134)
fmt.Printf("%v * 10^%v", c, e) // 1.3482339999999997 * 10^137
}

golang - modulus using math big package

Reading up the documentation - http://golang.org/pkg/math/big/
Mod sets z to the modulus x%y for y != 0 and returns z. If y == 0, a division-by-zero run-time panic occurs. Mod implements Euclidean modulus (unlike Go); see DivMod for more details.
10%4 = 2 but I get 8 with this (using the math/big package to do the same thing) - http://play.golang.org/p/_86etDvLYq
package main
import "fmt"
import "math/big"
import "strconv"
func main() {
ten := new(big.Int)
ten.SetBytes([]byte(strconv.Itoa(10)))
four := new(big.Int)
four.SetBytes([]byte(strconv.Itoa(4)))
tenmodfour := new(big.Int)
tenmodfour = tenmodfour.Mod(ten, four)
fmt.Println("mod", tenmodfour)
}
I most likely got something wrong. Where's the mistake?
It's because SetBytes is not doing what you think! Use SetInt64 instead.
ten := new(big.Int)
ten.SetBytes([]byte(strconv.Itoa(10)))
four := new(big.Int)
four.SetBytes([]byte(strconv.Itoa(4)))
fmt.Println(ten, four)
Result:
12592 52
And indeed, 12592%52 == 8
If you want to use numbers bigger than what int64 lets you manipulate, you can also use the SetString function:
n := new(big.Int)
n.SetString("456135478645413786350", 10)
Just an addition to julienc's answer, if you were to use SetBytes, you have to convert the number to bytes like this :
func int2bytes(num int) (b []byte) {
b = make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(num))
return
}
func main() {
ten := new(big.Int)
ten.SetBytes(int2bytes(10))
four := new(big.Int)
four.SetBytes(int2bytes(4))
fmt.Println(ten, four)
tenmodfour := new(big.Int)
tenmodfour = tenmodfour.Mod(ten, four)
fmt.Println("mod", tenmodfour)
}

Resources