Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add uint64 surport #131

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.git
*.swp
.idea/
350 changes: 182 additions & 168 deletions decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ func New(value int64, exp int32) Decimal {
}
}

// NewFromUint64 returns a new Decimal from a uint64, value * 10 ^ exp
func NewFromUint64(value uint64, exp int32) Decimal {
return Decimal{
value: new(big.Int).SetUint64(value),
exp: exp,
}
}

// NewFromBigInt returns a new Decimal from a big.Int, value * 10 ^ exp
func NewFromBigInt(value *big.Int, exp int32) Decimal {
return Decimal{
Expand Down Expand Up @@ -988,6 +996,12 @@ func (d *Decimal) Scan(value interface{}) error {
*d = New(v, 0)
return nil

case uint64:
// at least in clickhouse when the value is 0 in db, the data is sent
// to us as an uint64 instead of a int64 ...
*d = NewFromUint64(v, 0)
return nil

default:
// default is trying to interpret value stored as string
str, err := unquoteIfQuoted(v)
Expand Down Expand Up @@ -1261,174 +1275,174 @@ func (d Decimal) satan() Decimal {
}

// sin coefficients
var _sin = [...]Decimal{
NewFromFloat(1.58962301576546568060E-10), // 0x3de5d8fd1fd19ccd
NewFromFloat(-2.50507477628578072866E-8), // 0xbe5ae5e5a9291f5d
NewFromFloat(2.75573136213857245213E-6), // 0x3ec71de3567d48a1
NewFromFloat(-1.98412698295895385996E-4), // 0xbf2a01a019bfdf03
NewFromFloat(8.33333333332211858878E-3), // 0x3f8111111110f7d0
NewFromFloat(-1.66666666666666307295E-1), // 0xbfc5555555555548
}
var _sin = [...]Decimal{
NewFromFloat(1.58962301576546568060E-10), // 0x3de5d8fd1fd19ccd
NewFromFloat(-2.50507477628578072866E-8), // 0xbe5ae5e5a9291f5d
NewFromFloat(2.75573136213857245213E-6), // 0x3ec71de3567d48a1
NewFromFloat(-1.98412698295895385996E-4), // 0xbf2a01a019bfdf03
NewFromFloat(8.33333333332211858878E-3), // 0x3f8111111110f7d0
NewFromFloat(-1.66666666666666307295E-1), // 0xbfc5555555555548
}

// Sin returns the sine of the radian argument x.
func (d Decimal) Sin() Decimal {
PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts
PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000,
PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170,
M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi

if d.Equal(NewFromFloat(0.0)) {
return d
}
// make argument positive but save the sign
sign := false
if d.LessThan(NewFromFloat(0.0)) {
d = d.Neg()
sign = true
}

j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle
y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float

// map zeros to origin
if j&1 == 1 {
j++
y = y.Add(NewFromFloat(1.0))
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
// reflect in x axis
if j > 3 {
sign = !sign
j -= 4
}
z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic
zz := z.Mul(z)

if j == 1 || j == 2 {
w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5]))
y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w)
} else {
y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5])))
}
if sign {
y = y.Neg()
}
return y
}

// cos coefficients
var _cos = [...]Decimal{
NewFromFloat(-1.13585365213876817300E-11), // 0xbda8fa49a0861a9b
NewFromFloat(2.08757008419747316778E-9), // 0x3e21ee9d7b4e3f05
NewFromFloat(-2.75573141792967388112E-7), // 0xbe927e4f7eac4bc6
NewFromFloat(2.48015872888517045348E-5), // 0x3efa01a019c844f5
NewFromFloat(-1.38888888888730564116E-3), // 0xbf56c16c16c14f91
NewFromFloat(4.16666666666665929218E-2), // 0x3fa555555555554b
}

// Cos returns the cosine of the radian argument x.
func (d Decimal) Cos() Decimal {

PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts
PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000,
PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170,
M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi

// make argument positive
sign := false
if d.LessThan(NewFromFloat(0.0)) {
d = d.Neg()
}

j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle
y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float

// map zeros to origin
if j&1 == 1 {
j++
y = y.Add(NewFromFloat(1.0))
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
// reflect in x axis
if j > 3 {
sign = !sign
j -= 4
}
if j > 1 {
sign = !sign
}

z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic
zz := z.Mul(z)

if j == 1 || j == 2 {
y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5])))
} else {
w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5]))
y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w)
}
if sign {
y = y.Neg()
}
return y
}

var _tanP = [...]Decimal{
NewFromFloat(-1.30936939181383777646E+4), // 0xc0c992d8d24f3f38
NewFromFloat(1.15351664838587416140E+6), // 0x413199eca5fc9ddd
NewFromFloat(-1.79565251976484877988E+7), // 0xc1711fead3299176
}
var _tanQ = [...]Decimal{
NewFromFloat(1.00000000000000000000E+0),
NewFromFloat(1.36812963470692954678E+4), //0x40cab8a5eeb36572
NewFromFloat(-1.32089234440210967447E+6), //0xc13427bc582abc96
NewFromFloat(2.50083801823357915839E+7), //0x4177d98fc2ead8ef
NewFromFloat(-5.38695755929454629881E+7), //0xc189afe03cbe5a31
}

// Tan returns the tangent of the radian argument x.
func (d Decimal) Tan() Decimal {

PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts
PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000,
PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170,
M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi

if d.Equal(NewFromFloat(0.0)) {
return d
}
func (d Decimal) Sin() Decimal {
PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts
PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000,
PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170,
M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi

if d.Equal(NewFromFloat(0.0)) {
return d
}
// make argument positive but save the sign
sign := false
if d.LessThan(NewFromFloat(0.0)) {
d = d.Neg()
sign = true
}

j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle
y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float

// map zeros to origin
if j&1 == 1 {
j++
y = y.Add(NewFromFloat(1.0))
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
// reflect in x axis
if j > 3 {
sign = !sign
j -= 4
}
z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic
zz := z.Mul(z)

if j == 1 || j == 2 {
w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5]))
y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w)
} else {
y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5])))
}
if sign {
y = y.Neg()
}
return y
}

// cos coefficients
var _cos = [...]Decimal{
NewFromFloat(-1.13585365213876817300E-11), // 0xbda8fa49a0861a9b
NewFromFloat(2.08757008419747316778E-9), // 0x3e21ee9d7b4e3f05
NewFromFloat(-2.75573141792967388112E-7), // 0xbe927e4f7eac4bc6
NewFromFloat(2.48015872888517045348E-5), // 0x3efa01a019c844f5
NewFromFloat(-1.38888888888730564116E-3), // 0xbf56c16c16c14f91
NewFromFloat(4.16666666666665929218E-2), // 0x3fa555555555554b
}

// Cos returns the cosine of the radian argument x.
func (d Decimal) Cos() Decimal {

PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts
PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000,
PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170,
M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi

// make argument positive
sign := false
if d.LessThan(NewFromFloat(0.0)) {
d = d.Neg()
}

j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle
y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float

// make argument positive but save the sign
sign := false
if d.LessThan(NewFromFloat(0.0)) {
d = d.Neg()
sign = true
}

j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle
y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float

// map zeros to origin
if j&1 == 1 {
j++
y = y.Add(NewFromFloat(1.0))
}

z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic
zz := z.Mul(z)

if zz.GreaterThan(NewFromFloat(1e-14)) {
w := zz.Mul(_tanP[0].Mul(zz).Add(_tanP[1]).Mul(zz).Add(_tanP[2]))
x := zz.Add(_tanQ[1]).Mul(zz).Add(_tanQ[2]).Mul(zz).Add(_tanQ[3]).Mul(zz).Add(_tanQ[4])
y = z.Add(z.Mul(w.Div(x)))
} else {
y = z
}
if j&2 == 2 {
y = NewFromFloat(-1.0).Div(y)
}
if sign {
y = y.Neg()
}
return y
}
// map zeros to origin
if j&1 == 1 {
j++
y = y.Add(NewFromFloat(1.0))
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
// reflect in x axis
if j > 3 {
sign = !sign
j -= 4
}
if j > 1 {
sign = !sign
}

z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic
zz := z.Mul(z)

if j == 1 || j == 2 {
y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5])))
} else {
w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5]))
y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w)
}
if sign {
y = y.Neg()
}
return y
}

var _tanP = [...]Decimal{
NewFromFloat(-1.30936939181383777646E+4), // 0xc0c992d8d24f3f38
NewFromFloat(1.15351664838587416140E+6), // 0x413199eca5fc9ddd
NewFromFloat(-1.79565251976484877988E+7), // 0xc1711fead3299176
}
var _tanQ = [...]Decimal{
NewFromFloat(1.00000000000000000000E+0),
NewFromFloat(1.36812963470692954678E+4), //0x40cab8a5eeb36572
NewFromFloat(-1.32089234440210967447E+6), //0xc13427bc582abc96
NewFromFloat(2.50083801823357915839E+7), //0x4177d98fc2ead8ef
NewFromFloat(-5.38695755929454629881E+7), //0xc189afe03cbe5a31
}

// Tan returns the tangent of the radian argument x.
func (d Decimal) Tan() Decimal {

PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts
PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000,
PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170,
M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi

if d.Equal(NewFromFloat(0.0)) {
return d
}

// make argument positive but save the sign
sign := false
if d.LessThan(NewFromFloat(0.0)) {
d = d.Neg()
sign = true
}

j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle
y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float

// map zeros to origin
if j&1 == 1 {
j++
y = y.Add(NewFromFloat(1.0))
}

z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic
zz := z.Mul(z)

if zz.GreaterThan(NewFromFloat(1e-14)) {
w := zz.Mul(_tanP[0].Mul(zz).Add(_tanP[1]).Mul(zz).Add(_tanP[2]))
x := zz.Add(_tanQ[1]).Mul(zz).Add(_tanQ[2]).Mul(zz).Add(_tanQ[3]).Mul(zz).Add(_tanQ[4])
y = z.Add(z.Mul(w.Div(x)))
} else {
y = z
}
if j&2 == 2 {
y = NewFromFloat(-1.0).Div(y)
}
if sign {
y = y.Neg()
}
return y
}