How should we calc money (decimal, big.Float) - go

Can someone tell the right way to calculate finance data in Go. I tryed to use big.Float but prob I miss something. The core goal is to calculate numbers with flaoting point and precision from 2 to 4 without any losses.
0.15 + 0.15 always should be 0.30.
float try:
https://play.golang.org/p/_3CXtRRNcA0
big.Float try:
https://play.golang.org/p/zegE__Dit1O

Floating-point is imprecise. Use integers (int64) scaled to cents or fractional cents.
For example, cents,
package main
import (
"fmt"
)
func main() {
cents := int64(0)
for i := 0; i <= 2; i++ {
cents += 15
fmt.Println(cents)
}
fmt.Printf("$%d.%02d\n", cents/100, cents%100)
}
Playground: https://play.golang.org/p/k4mJZFRUGVH
Output:
15
30
45
$0.45
For example, hundredths of a cent rounded,
package main
import "fmt"
func main() {
c := int64(0) // hundredths of a cent
for i := 0; i <= 2; i++ {
c += 1550
fmt.Println(c)
}
c += 50 // rounded
fmt.Printf("$%d.%02d\n", c/10000, c%10000/100)
}
Playground: https://play.golang.org/p/YGW9SC7OcU3
Output:
1550
3100
4650
$0.47

you can try https://github.com/shopspring/decimal if you really concern about precision,
try this code:
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
z := decimal.NewFromFloat(0)
b := decimal.NewFromFloat(0.15)
z = z.Add(b)
z = z.Add(b)
z = z.Add(b)
fmt.Println("z value:", z)
testz := z.Cmp(decimal.NewFromFloat(0.45)) == 0
fmt.Println("is z pass the test? ", testz)
}
Playground: https://play.golang.org/p/g_fSGlXPKDH
Output:
z value: 0.45
is z pass the test? true

Related

Absolute difference between time.Duration

I have 2 variables with time.Duration type. I need to find the difference in duration between them.
For example:
v1 = 1sec and v2 = 10sec — difference is 9 sec.
v1 = 10sec and v2 = 1sec — difference is also 9 sec.
Both variables can have different values for hours, minutes etc.
How can I do this in Go?
Try this:
package main
import (
"fmt"
"time"
)
func main() {
a := 1 * time.Second
b := 10 * time.Second
c := absDiff(a, b)
fmt.Println(c) // 9s
fmt.Println(absDiff(b, a)) // 9s
}
func absDiff(a, b time.Duration) time.Duration {
if a >= b {
return a - b
}
return b - a
}
This is another form:
package main
import (
"fmt"
"time"
)
func main() {
a := 1 * time.Second
b := 10 * time.Second
c := abs(a - b)
fmt.Println(c) // 9s
}
func abs(a time.Duration) time.Duration {
if a >= 0 {
return a
}
return -a
}
Go 1.19
The function Abs has been added to the language, so you can just use that instead of rolling your own:
func main() {
d1 := time.Second * 10
d2 := time.Second
sub1 := d1 - d2
sub2 := d2 - d1
fmt.Println(sub1.Abs()) // 9s
fmt.Println(sub2.Abs()) // 9s
}
An elegant solution is to use bitshift >>
func absDuration(d time.Duration) time.Duration {
s := d >> 63
return (d ^ s) - s
}
bitshift in Golang is logic if the left operand is negative

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

Golang exercise slices how does it deal with big values

I'm going through the Golang tutorial and I'm a little bit confused as to what it is doing with some of the values in the slices exercise. https://tour.golang.org/moretypes/18
Here is the code that I am confused with:
A value of 0 is a perfectly blue pixel and a value of 255 is a perfectly white pixel. So what is happening here when the value displayed is some form of x*y (I did /20 to make the image a little bit bigger and easier to see).
If you follow the image horizontally, you will see that at some point in the process, the ever increasing x and y values seem to revert to blue (0 value) If I type a static value like 256 in the return I get a compile error. So it obviously does not allow the numbers to go off the scale and revert to 0 or anything. So how does it get the blue curves in the picture?
imported source here: https://github.com/golang/tour/blob/master/pic/pic.go#L15
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
//First, the array has to be made so we can put some values in it later
//This only makes the second dimension of the array ([[uint8 dy]])?
image := make([][]uint8, dy)
//The inputs into the function are Int's, so it is ok to have a non uint8
//loop initializer
for x := 0; x < dy; x++ {
//once we are in the loop we have to make the first dimension of the array
//based on the dx values
image[x] = make([]uint8, dx)
for y := 0; y < dx; y++ {
//This is a function +to assign the pixel values to the array
image[x][y] = uint8((x * y) /20)
}
}
return image
}
func main() {
pic.Show(Pic)
}
Imagine i is of type int, uint8(i) returns Least Significant Byte (LSB) of i:
When x is in range [0, 255] , meaning: 0 <= x <= 255
and y is in range [0, 255],
then x*y is in range [0, 255*255] = [0, 65025]
so x*y/20 is in range [0, 255*255/20] = [0, 65025/20] = [0, 3251]
and value of uint8(x*y/20) is equal to (x*y/20)%256 meaning exactly LSB byte:
uint8(3251) = uint8(0XCB3) = 0XB3 = 179
3251 = 12*256 + 179
So every time the x*y/20 is bigger than 255 it counts from 0 again: (x*y/20) % 256 this is why your image is repeated circles.
Try this working sample code:
package main
import "fmt"
func main() {
for y := 0; y <= 255; y++ {
for x := 0; x <= 255; x++ {
v := x * y / 20
if int(uint8(v)) != v%256 {
fmt.Println(v, v%256)
}
}
}
fmt.Println("Done.")
}
output:
Done.
Let's simplify you example, see this working sample code:
package main
import (
"bytes"
"image"
"image/png"
"os"
)
func main() {
const dx = 256
const dy = 256
m := image.NewNRGBA(image.Rect(0, 0, dx, dy))
for y := 0; y < dy; y++ {
for x := 0; x < dx; x++ {
v := uint8(x * y / 20)
i := y*m.Stride + x*4
m.Pix[i] = v //R
m.Pix[i+1] = v //G
m.Pix[i+2] = 255 //B
m.Pix[i+3] = 255 //A
}
}
var buf bytes.Buffer
err := png.Encode(&buf, m)
if err != nil {
panic(err)
}
os.Stdout.Write(buf.Bytes())
}
And redirect the output to a file like main > b.png or, go run main.go > b.png
see output file b.png:
uint8(anotherIntValue) conversion will take the last byte of anotherIntValue. That is why your code can produce many blue (0). For example, following code would print 'val = 0'.
dx, dy := 128, 2
fmt.Println("val =", uint8(dx*dy))
Constant conversion will be checked by compiler for out of range errors.

How to test whether a float is a whole number in Go?

I originally tried this, however the % operator isn't defined for float64.
func main(){
var a float64
a = 1.23
if a%1 == 0{
fmt.Println("yay")
}else{
fmt.Println("you fail")
}
}
Assuming that your numbers will fit into an int64, you can compare the float value with a converted integer value to see if they're the same:
if a == float64(int64(a)) { ... }
Alternatively, if you need the entire float64 domain, you can use the math.Trunc function, with something like:
if a == math.Trunc(a) { ... }
For example, the following code correctly outputs yay, on testing over at the Go playground:
package main
import (
"fmt"
"math"
)
func main() {
var a float64 = 2.00
if a == math.Trunc(a) {
fmt.Println("yay")
} else {
fmt.Println("you fail")
}
}
You can use the math.Modf function:
const epsilon = 1e-9 // Margin of error
if _, frac := math.Modf(math.Abs(a)); frac < epsilon || frac > 1.0 - epsilon {
// ...
}
epsilon is necessary here since floating point math is not precise (e.g. float64(.3)+float64(.6)+float64(.1) != 1)
From the godoc:
func Modf(f float64) (int float64, frac float64)
Modf returns integer and fractional floating-point numbers that sum to f. Both values have the same sign as f.
How about math.Trunc? It truncates a float64 to its whole-number component.
For example, something like:
if a.Trunc() == a {
// ...
}
Beware of the usual considerations about floating-point representation limitations. You might wish to check whether a.Trunc() is within some small range of a, to account for values like 1.00000000000000002.
I solved it like so:
isWhole := int(value * 100) == int(value) * 100
Adjust the number of digits in the factor, e.g. multiply by 10000 to check 4 digits.
I think the following code might be useful,
func main(){
var (
a float64
b float64
c float64
)
a = 1.23
b = float64(int64(a))
c = a - b
if c > 0 {
fmt.Println("Not a Whole Number")
} else {
fmt.Println("Whole Number")
}
}

How to take a cube root in Go?

I'm writing a cube root function in Google Go using Newton's method. I want to check the results using math/cmplx.Pow(), but for the life of me, I can't figure out how. How do I do this?
Have you tried myCubicRootOfx = Pow(x, 1.0/3) ?
edited: thanks to Jason McCreary comment:
We cannot use 1/3 as the 2nd parameter to Pow as this is a integer division and hence doesn't produce the expected 1/3 value. By using 1.0/3 or 1/3.0 etc. we effectively produce a float with the 0.333333... value.
I wrote the cube root function using Newton's method as part of the Go Tour Exercise 47. Perhaps the two functions below (Cbrt1 and Cbrt) are helpful.
package main
import (
"fmt"
"math/cmplx"
)
// Newton's method cube root function that hopes for
// convergence within 20 iterations
func Cbrt1(x complex128) complex128 {
var z complex128 = x
for i:= 0; i < 20; i++ {
z = z - ((z*z*z - x) / (3.0*z*z))
}
return z
}
// Newton's method cube root function that runs until stable
func Cbrt(x complex128) complex128 {
var z, z0 complex128 = x, x
for {
z = z - ((z*z*z - x) / (3.0*z*z))
if cmplx.Abs(z - z0) < 1e-10 {
break
}
z0 = z
}
return z
}
func main() {
fmt.Println(Cbrt(2.0) , "should match" , cmplx.Pow(2, 1.0/3.0))
}
As you're using Newton's method, I suppose you're starting with a positive real number.
So you don't need complex numbers.
You may simply do
package main
import (
"fmt"
"math"
)
func main() {
x := 100.0
root := math.Pow(x, 1.0/3.0)
fmt.Println(root)
}
For example,
package main
import (
"fmt"
"math/cmplx"
)
func main() {
var x complex128
x = -8
y := cmplx.Pow(x, 1.0/3.0)
fmt.Println(y)
x = -27i
y = cmplx.Pow(x, 1.0/3.0)
fmt.Println(y)
x = -8 - 27i
y = cmplx.Pow(x, 1.0/3.0)
fmt.Println(y)
x = complex(-8, -27)
y = cmplx.Pow(x, 1.0/3.0)
fmt.Println(y)
}
Output:
(1+1.732050807568877i)
(2.5980762113533156-1.4999999999999996i)
(2.4767967587776756-1.7667767800295509i)
(2.4767967587776756-1.7667767800295509i)
The Go Programming Language Specification
Package cmplx
Looks like go has changed more recently than some of the other answers, so I figured I would update - they built cuberoot right into math as Cbrt. It takes, and returns, a float64. A quick reference is at godoc math | grep Cbrt (if you've got godoc installed, which I highly recommend)
import "math"
func main() {
var x float64 = math.Cbrt(8)
fmt.Println(x) // prints 2
}
try something like this
package main
import(
"fmt"
"math/cmplx"
)
func Cbrt(x complex128) complex128 {
z := complex128(1)
for i:=0;i<100;i++ { // OR JUST for{ since you will outrun complex128 in worth case
last_z := z
z = z - ((z*z*z - x)/(3 *z*z))
if last_z == z{
return z
}
}
return z
}
func main() {
fmt.Println("good enough", Cbrt(9))
fmt.Println("builtin", cmplx.Pow(9, 1.0/3.0))
}

Resources