Added support for Decimal places in JSON marshall

This commit is contained in:
Carl Cudors 2018-10-14 17:31:30 +03:00
parent cd690d0c9e
commit cbaf07db27

View file

@ -52,6 +52,10 @@ var DivisionPrecision = 16
// silently lose precision. // silently lose precision.
var MarshalJSONWithoutQuotes = false var MarshalJSONWithoutQuotes = false
// If Set to True, returns rounded fixed-point string with places digits after the decimal point
var MarshalJSONWithDecimalPlaces = false
var MarshalJSONDecimalPlaces = 0
// Zero constant, to make computations faster. // Zero constant, to make computations faster.
var Zero = New(0, 1) var Zero = New(0, 1)
@ -931,11 +935,18 @@ func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error {
// MarshalJSON implements the json.Marshaler interface. // MarshalJSON implements the json.Marshaler interface.
func (d Decimal) MarshalJSON() ([]byte, error) { func (d Decimal) MarshalJSON() ([]byte, error) {
var stringVal string
if MarshalJSONWithDecimalPlaces {
stringVal = d.StringFixed(MarshalJSONDecimalPlaces)
} else {
stringVal = d.String()
}
var str string var str string
if MarshalJSONWithoutQuotes { if MarshalJSONWithoutQuotes {
str = d.String() str = stringVal
} else { } else {
str = "\"" + d.String() + "\"" str = "\"" + stringVal + "\""
} }
return []byte(str), nil return []byte(str), nil
} }
@ -1261,174 +1272,174 @@ func (d Decimal) satan() Decimal {
} }
// sin coefficients // sin coefficients
var _sin = [...]Decimal{ var _sin = [...]Decimal{
NewFromFloat(1.58962301576546568060E-10), // 0x3de5d8fd1fd19ccd NewFromFloat(1.58962301576546568060E-10), // 0x3de5d8fd1fd19ccd
NewFromFloat(-2.50507477628578072866E-8), // 0xbe5ae5e5a9291f5d NewFromFloat(-2.50507477628578072866E-8), // 0xbe5ae5e5a9291f5d
NewFromFloat(2.75573136213857245213E-6), // 0x3ec71de3567d48a1 NewFromFloat(2.75573136213857245213E-6), // 0x3ec71de3567d48a1
NewFromFloat(-1.98412698295895385996E-4), // 0xbf2a01a019bfdf03 NewFromFloat(-1.98412698295895385996E-4), // 0xbf2a01a019bfdf03
NewFromFloat(8.33333333332211858878E-3), // 0x3f8111111110f7d0 NewFromFloat(8.33333333332211858878E-3), // 0x3f8111111110f7d0
NewFromFloat(-1.66666666666666307295E-1), // 0xbfc5555555555548 NewFromFloat(-1.66666666666666307295E-1), // 0xbfc5555555555548
} }
// Sin returns the sine of the radian argument x. // Sin returns the sine of the radian argument x.
func (d Decimal) Sin() Decimal { func (d Decimal) Sin() Decimal {
PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts
PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000, PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000,
PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170, PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170,
M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi
if d.Equal(NewFromFloat(0.0)) { if d.Equal(NewFromFloat(0.0)) {
return d return d
} }
// make argument positive but save the sign // make argument positive but save the sign
sign := false sign := false
if d.LessThan(NewFromFloat(0.0)) { if d.LessThan(NewFromFloat(0.0)) {
d = d.Neg() d = d.Neg()
sign = true sign = true
} }
j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle 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 y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float
// map zeros to origin // map zeros to origin
if j&1 == 1 { if j&1 == 1 {
j++ j++
y = y.Add(NewFromFloat(1.0)) y = y.Add(NewFromFloat(1.0))
} }
j &= 7 // octant modulo 2Pi radians (360 degrees) j &= 7 // octant modulo 2Pi radians (360 degrees)
// reflect in x axis // reflect in x axis
if j > 3 { if j > 3 {
sign = !sign sign = !sign
j -= 4 j -= 4
} }
z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic
zz := z.Mul(z) zz := z.Mul(z)
if j == 1 || j == 2 { 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])) 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) y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w)
} else { } 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]))) 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 { if sign {
y = y.Neg() y = y.Neg()
} }
return y return y
} }
// cos coefficients // cos coefficients
var _cos = [...]Decimal{ var _cos = [...]Decimal{
NewFromFloat(-1.13585365213876817300E-11), // 0xbda8fa49a0861a9b NewFromFloat(-1.13585365213876817300E-11), // 0xbda8fa49a0861a9b
NewFromFloat(2.08757008419747316778E-9), // 0x3e21ee9d7b4e3f05 NewFromFloat(2.08757008419747316778E-9), // 0x3e21ee9d7b4e3f05
NewFromFloat(-2.75573141792967388112E-7), // 0xbe927e4f7eac4bc6 NewFromFloat(-2.75573141792967388112E-7), // 0xbe927e4f7eac4bc6
NewFromFloat(2.48015872888517045348E-5), // 0x3efa01a019c844f5 NewFromFloat(2.48015872888517045348E-5), // 0x3efa01a019c844f5
NewFromFloat(-1.38888888888730564116E-3), // 0xbf56c16c16c14f91 NewFromFloat(-1.38888888888730564116E-3), // 0xbf56c16c16c14f91
NewFromFloat(4.16666666666665929218E-2), // 0x3fa555555555554b NewFromFloat(4.16666666666665929218E-2), // 0x3fa555555555554b
} }
// Cos returns the cosine of the radian argument x. // Cos returns the cosine of the radian argument x.
func (d Decimal) Cos() Decimal { func (d Decimal) Cos() Decimal {
PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts
PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000, PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000,
PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170, PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170,
M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi
// make argument positive // make argument positive
sign := false sign := false
if d.LessThan(NewFromFloat(0.0)) { if d.LessThan(NewFromFloat(0.0)) {
d = d.Neg() d = d.Neg()
} }
j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle 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 y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float
// map zeros to origin // map zeros to origin
if j&1 == 1 { if j&1 == 1 {
j++ j++
y = y.Add(NewFromFloat(1.0)) y = y.Add(NewFromFloat(1.0))
} }
j &= 7 // octant modulo 2Pi radians (360 degrees) j &= 7 // octant modulo 2Pi radians (360 degrees)
// reflect in x axis // reflect in x axis
if j > 3 { if j > 3 {
sign = !sign sign = !sign
j -= 4 j -= 4
} }
if j > 1 { if j > 1 {
sign = !sign sign = !sign
} }
z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic
zz := z.Mul(z) zz := z.Mul(z)
if j == 1 || j == 2 { 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]))) 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 { } 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])) 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) y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w)
} }
if sign { if sign {
y = y.Neg() y = y.Neg()
} }
return y return y
} }
var _tanP = [...]Decimal{ var _tanP = [...]Decimal{
NewFromFloat(-1.30936939181383777646E+4), // 0xc0c992d8d24f3f38 NewFromFloat(-1.30936939181383777646E+4), // 0xc0c992d8d24f3f38
NewFromFloat(1.15351664838587416140E+6), // 0x413199eca5fc9ddd NewFromFloat(1.15351664838587416140E+6), // 0x413199eca5fc9ddd
NewFromFloat(-1.79565251976484877988E+7), // 0xc1711fead3299176 NewFromFloat(-1.79565251976484877988E+7), // 0xc1711fead3299176
} }
var _tanQ = [...]Decimal{ var _tanQ = [...]Decimal{
NewFromFloat(1.00000000000000000000E+0), NewFromFloat(1.00000000000000000000E+0),
NewFromFloat(1.36812963470692954678E+4), //0x40cab8a5eeb36572 NewFromFloat(1.36812963470692954678E+4), //0x40cab8a5eeb36572
NewFromFloat(-1.32089234440210967447E+6), //0xc13427bc582abc96 NewFromFloat(-1.32089234440210967447E+6), //0xc13427bc582abc96
NewFromFloat(2.50083801823357915839E+7), //0x4177d98fc2ead8ef NewFromFloat(2.50083801823357915839E+7), //0x4177d98fc2ead8ef
NewFromFloat(-5.38695755929454629881E+7), //0xc189afe03cbe5a31 NewFromFloat(-5.38695755929454629881E+7), //0xc189afe03cbe5a31
} }
// Tan returns the tangent of the radian argument x. // Tan returns the tangent of the radian argument x.
func (d Decimal) Tan() Decimal { func (d Decimal) Tan() Decimal {
PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts
PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000, PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000,
PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170, PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170,
M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi
if d.Equal(NewFromFloat(0.0)) { if d.Equal(NewFromFloat(0.0)) {
return d return d
} }
// make argument positive but save the sign // make argument positive but save the sign
sign := false sign := false
if d.LessThan(NewFromFloat(0.0)) { if d.LessThan(NewFromFloat(0.0)) {
d = d.Neg() d = d.Neg()
sign = true sign = true
} }
j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle 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 y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float
// map zeros to origin // map zeros to origin
if j&1 == 1 { if j&1 == 1 {
j++ j++
y = y.Add(NewFromFloat(1.0)) y = y.Add(NewFromFloat(1.0))
} }
z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic
zz := z.Mul(z) zz := z.Mul(z)
if zz.GreaterThan(NewFromFloat(1e-14)) { if zz.GreaterThan(NewFromFloat(1e-14)) {
w := zz.Mul(_tanP[0].Mul(zz).Add(_tanP[1]).Mul(zz).Add(_tanP[2])) 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]) 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))) y = z.Add(z.Mul(w.Div(x)))
} else { } else {
y = z y = z
} }
if j&2 == 2 { if j&2 == 2 {
y = NewFromFloat(-1.0).Div(y) y = NewFromFloat(-1.0).Div(y)
} }
if sign { if sign {
y = y.Neg() y = y.Neg()
} }
return y return y
} }