ericlagergren / decimal

A high-performance, arbitrary-precision, floating-point decimal library.
https://godoc.org/github.com/ericlagergren/decimal
BSD 3-Clause "New" or "Revised" License
518 stars 61 forks source link

math: Pow returns wrong results when base is negative and power is an integer #164

Closed songmelted closed 3 years ago

songmelted commented 3 years ago

https://play.golang.org/p/90KVPuJF2fm

package main

import (
    "fmt"
    "math"

    "github.com/ericlagergren/decimal"
    dmath "github.com/ericlagergren/decimal/math"
)

func main() {
    x := uint64(3)
    y := uint64(4)

    z1 := new(decimal.Big).SetUint64(0)
    z2 := float64(0)

    x1 := new(decimal.Big).SetUint64(x)
    x2 := float64(x)

    y1 := new(decimal.Big).SetUint64(y)
    y2 := float64(y)

    z1 = dmath.Pow(z1, x1, y1)
    z2 =  math.Pow    (x2, y2)
    fmt.Println(z1, " == ", z2)

    z1 = dmath.Pow(z1, x1,  y1.Neg(y1))
    z2 =  math.Pow(    x2, -y2)
    fmt.Println(z1, " == ", z2)

    z1 = dmath.Pow(z1, x1.Neg(x1), y1)
    z2 =  math.Pow          (-x2,  y2)
    fmt.Println(z1, " != ", z2)//These should be equal, but are not.

    z1 = dmath.Pow(z1, x1.Neg(x1), y1.Neg(y1))
    z2 =  math.Pow          (-x2,        -y2)
    fmt.Println(z1, " != ", z2)//These should be equal, but are not.

}

This code outputs:

81  ==  81
0.01234567901234568  ==  0.012345679012345678
0.01234567901234568  !=  81
81  !=  0.012345679012345678

Bug is difficult to reproduce. Sometimes, similar code will not result in the bug for reasons not immediately clear.

songmelted commented 3 years ago

This example code is flawed and the bug is not in the decimal package.

In my haste to make a simple example, I made a bug as well.