shopspring / decimal Goto Github PK
View Code? Open in Web Editor NEWArbitrary-precision fixed-point decimal numbers in Go
License: Other
Arbitrary-precision fixed-point decimal numbers in Go
License: Other
Currently there is error when reading from database where source field is NULL. Please add NullDecimal type so that everyone doesn't need to roll their own.
type NullDecimal struct {
Decimal Decimal
Valid bool // Valid is true if Decimal is not NULL
}
// Scan implements the Scanner interface.
func (nd *NullDecimal) Scan(value interface{}) error {
if value == nil {
nd.Decimal, nd.Valid = Zero, false
return nil
}
nd.Valid = true
return nd.Scan(value)
}
// Value implements the driver Valuer interface.
func (nd NullDecimal) Value() (driver.Value, error) {
if !nd.Valid {
return nil, nil
}
return nd.Decimal.String(), nil
}
Hey,
this issue is just a FYI and can be closed or to be worked on ;-)
Comparison table: https://github.com/ericlagergren/decimal/tree/master/benchmarks
This can easily be coded from the sign function and subtract function... I'll do this unless there is some resistance to including this
This used to pass.
func TestNumericFromFloat(t *testing.T) {
fromString, err := decimal.NewFromString("12345.678901")
if err != nil {
t.Fatal(err)
}
fromFloat := decimal.NewFromFloat(12345.678901)
if !fromString.Equal(fromFloat) {
t.Fatalf("expected fromString (%v) to equal fromFloat (%v) but it doesn't", fromString, fromFloat)
}
}
But is doesn't pass as of 78e9b82.
--- FAIL: TestNumericFromFloat (0.00s)
decimal_test.go:157: expected fromString (12345.678901) to equal fromFloat (12345.6789009999993140809237957000732421875) but it doesn't
fmt.Println(decimal.NewFromFloat(3.5).RoundCash(15))
the result Is 2.4
fmt.Println(decimal.NewFromFloat(3.45).RoundCash(15))
the result is 3.5 , not same with the doc.
New(1,1).Ceil()
and New(1,1).Floor()
return 1. Calling the same functions for New(10,0)
gives 10 which is the expected value in both cases. Unless I missed something here, it looks like a bug.
#64 provides more details and suggests a possible solution.
I have strict json parser as a consumer of an api using the Decimal type. Is there a way to Marshal as a number rather than a string? The quotes seem to be hardcoded right now in the marshal.
First off, awesome library.
I noticed that there are some new pull and feature requests recently. I currently have the time and motivation to work on this project to try to knock some of these out. Let me know if I can offer my services to be a maintainer of this project.
Hi,
Would be great to have Float() function in addition to String(), to be able to get a float64 value from a decimal.
Thanks!
decimal.Zero should be removed unless the following code is valid:
if d == decimal.Zero {
}
Let's say you have a system that accepts prices over API. Someone sends in a price in USD of $0.333, but you only accept orders to the nearest cent. So you truncate their order to $0.33. Fine.
But what happens if they submit an order of $0.003? Now you've truncated their order to $0.00, which should just be rejected. What's the best way to check for something like this? I tried just doing a raw equality check against decimal.Zero
but that fails the equality check, and I couldn't see anything obvious in the source for such a check.
func Decimal() {
f, exit := decimal.NewFromFloat(1.275).Round(2).Float64()
if exit {
fmt.Println("yes")
}
fmt.Println(f)
// result should be 1.28, but got 1.27
}
I'm still new to Go, so why I got what I don't want, can anybody explain ,thx.
Is there any way to fix this?
I don't see a format option for thousands separators, such as commas. Am I missing it?
This is arguably of course. In my opinion NewFromFloatWithPrecision(value float64, prec int32) is much more friendly name than NewFromFloatWithExponent(value float64, exp int32). Probably not all people working with decimal numbers know what is exponent. Argument prec should be treated as -exp in this case and current method should be deprecated.
Frankly speaking I would go further and deprecate NewFromFloat in favor of NewFromFloatExact. This should make people think about memory needed to store float without specifying precision.
What would be the correct way to handle this operations to get exactly the initial 0.19 back?
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
p := decimal.NewFromFloat(0.19)
sixty := decimal.NewFromFloat(60)
r := p.Div(sixty)
fmt.Println("Results: ", r, r.Mul(sixty))
}
Thanks,
-rif
What is preferred way to compare decimals with 0?
Does decimal.Zero can be used?
Hi @vadimg, thanks for your work on this library. Have you considered adding support for the notions of either NaN
or +/-Inf
? If not, would you be opposed to me taking a shot at introducing them? I think both would be nice to have, but the notion of infinity especially would make this library an even more comparable replacement to big.Float
.
I think the java's BigDecimal is a very good guid to follow.
Functions like movePoint or neg is very useful, current I use decimal like this to do that
func toDecimal(precision int, scale int, value []byte) decimal.Decimal {
positive := value[0] & 0x80 == 0x80
value[0] ^= 0x80
if (!positive) {
for i := 0; i < len(value); i++ {
value[i] ^= 0xFF;
}
}
x := precision - scale
ipDigits := x / _DIG_PER_DEC
ipDigitsX := x - ipDigits * _DIG_PER_DEC
ipSize := (ipDigits << 2) + int(_DIG_TO_BYTES[ipDigitsX])
offset := int(_DIG_TO_BYTES[ipDigitsX])
ip := decimal.Zero
if offset > 0 {
ip = decimal.NewFromFloat(float64(bigEndianInteger(value, 0, offset)))
}
for ; offset < ipSize; offset += 4 {
i := bigEndianInteger(value, offset, 4);
ip = ip.Mul(decimal.NewFromFloat(math.Pow10(_DIG_PER_DEC))).Add(decimal.NewFromFloat(float64(i)))
}
shift := 0
fp := decimal.Zero
for ; shift + _DIG_PER_DEC <= scale; shift, offset =shift+ _DIG_PER_DEC, offset + 4 {
i := bigEndianInteger(value, offset, 4);
fp = fp.Add(decimal.NewFromFloat(float64(i)).Div(decimal.NewFromFloat(math.Pow10(shift+_DIG_PER_DEC))))
}
if shift < scale {
i := bigEndianInteger(value, offset, int(_DIG_TO_BYTES[scale - shift]));
fp = fp.Add(decimal.NewFromFloat(float64(i)).Div(decimal.NewFromFloat(math.Pow10(scale))))
}
result := ip.Add(fp)
if (positive) {
return result
}
return result.Mul(decimal.NewFromFloat(-1))
}
Code like .Div(decimal.NewFromFloat(math.Pow10(shift+_DIG_PER_DEC)))
is very unreadable, it's just movePointLeft(shift+_DIG_PER_DEC)
The RoundBank()
function, given the decimal value 2.5
, should return 2
. This works as expected when your decimal is represented by New(25, -1)
.
However, when represented by New(250, -2)
, the function RoundBank()
gives the incorrect result of 3
.
Here is a currently failing test which illustrates the problem:
func TestRoundBankAnomaly(t *testing.T) {
a := New(25, -1)
b := New(250, -2)
if !a.Equal(b) {
t.Errorf("Expected %s to equal %s", a, b)
}
expected := New(2, 0)
aRounded := a.RoundBank(0)
if !aRounded.Equal(expected) {
t.Errorf("Expected bank rounding %s to equal %s, but it was %s", a, expected, aRounded)
}
bRounded := b.RoundBank(0)
if !bRounded.Equal(expected) {
t.Errorf("Expected bank rounding %s to equal %s, but it was %s", b, expected, bRounded)
}
}
As title says, when adding two MaxInt64s, I got the wrong number:
d1 := decimal.NewFromFloat(math.MaxInt64).Add(decimal.NewFromFloat(math.MaxInt64))
fmt.Printf("d1=%s\n", d1.String()) //result: -18446744073709551616
Here is the golang's big package example:
var x, y, z big.Float
x.SetInt64(math.MaxInt64)
y.SetFloat64(math.MaxInt64)
z.SetPrec(32)
z.Add(&x, &y)
fmt.Printf("z=%.40g\n", &z) // result: 18446744073709551616
Hi, after commit 78e9b82 NewFromFloat works not as it should
fmt.Println(decimal.NewFromFloat(0.1).String()) fmt.Println(decimal.NewFromFloat(0.01).String()) fmt.Println(decimal.NewFromFloat(0.02).String()) fmt.Println(decimal.NewFromFloat(0.0023).String()) fmt.Println(decimal.NewFromFloat(0.69).String()) fmt.Println(decimal.NewFromFloat(0.98).String())
return
0.1000000000000000055511151231257827021181583404541015625
0.01000000000000000020816681711721685132943093776702880859375
0.0200000000000000004163336342344337026588618755340576171875
0.0022999999999999999611421941381195210851728916168212890625
0.689999999999999946709294817992486059665679931640625
0.979999999999999982236431605997495353221893310546875
Reverting back to commit bf9a39e works as it should:
0.1
0.01
0.02
0.0023
0.69
0.98
Tested on go version go1.9.2 linux/amd64
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Model name: Intel(R) Core(TM) i3-4170 CPU @ 3.70GHz
when save to mongodb with mgo, decimal.Decimal is empty. Is it bson serialize needed?
as title indicates issue is when used in struct and a retrieved value is an empty string, omitempty is no help. This makes using the library hard as when pulling in data from outside sources you don't know when they could could suddenly do this, and this error is than breaking because no data will be unmarshaled
type example struct { Value decimal.Decimal json:"value, omitempty" }
relevant code in library :
// UnmarshalJSON implements the json.Unmarshaler interface.
func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error {
if string(decimalBytes) == "null" {
return nil
}
str, err := unquoteIfQuoted(decimalBytes)
if err != nil {
return fmt.Errorf("Error decoding string '%s': %s", decimalBytes, err)
}
decimal, err := NewFromString(str)
*d = decimal
if err != nil {
return fmt.Errorf("Error decoding string '%s': %s", str, err)
}
return nil
and :
func NewFromString(value string) (Decimal, error) {
originalInput := value
var intString string
var exp int64
// Check if number is using scientific notation
eIndex := strings.IndexAny(value, "Ee")
if eIndex != -1 {
expInt, err := strconv.ParseInt(value[eIndex+1:], 10, 32)
if err != nil {
if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange {
return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", value)
}
return Decimal{}, fmt.Errorf("can't convert %s to decimal: exponent is not numeric", value)
}
value = value[:eIndex]
exp = expInt
}
parts := strings.Split(value, ".")
if len(parts) == 1 {
// There is no decimal point, we can just parse the original string as
// an int
intString = value
} else if len(parts) == 2 {
// strip the insignificant digits for more accurate comparisons.
decimalPart := strings.TrimRight(parts[1], "0")
intString = parts[0] + decimalPart
expInt := -len(decimalPart)
exp += int64(expInt)
} else {
return Decimal{}, fmt.Errorf("can't convert %s to decimal: too many .s", value)
}
dValue := new(big.Int)
_, ok := dValue.SetString(intString, 10)
if !ok {
return Decimal{}, fmt.Errorf("can't convert %s to decimal", value)
}
if exp < math.MinInt32 || exp > math.MaxInt32 {
// NOTE(vadim): I doubt a string could realistically be this long
return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", originalInput)
}
return Decimal{
value: dValue,
exp: int32(exp),
}, nil
}
there is a check for scientific notation, and a check if there is a decimal, but none for an empty string,
there seems to be 2 ways to fix this, either conform if possible to the omitempty with golang json, if this is not possible than add a check for empty values and return 0 value int, similar to the "is no decimal point we can just parse the original string as an int"
looking at closed issues and the code further I see fix for null, possibly just add "" as well eg :
func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error {
- if string(decimalBytes) == "null" {
+ if string(decimalBytes) == "null" || string(decimalBytes) == "" {
return nil
}
Decimal implements JSON and text marshalling. This allows for encoding to json, xml and other text-based encoders. Encoding to binary (like with encoding/gob) does not work because the type does not implement BinaryMarshaler and BinaryUnmarshaler interfaces.
The current implementation of Pow
only looks at the IntPart
of the exponent, so something like 4^2.5 returns 16 :(
I'm not sure why the exponent argument is supposed to be a decimal if it actually only works for ints.
decimal.NewFromString("512e-3")
errors out. Is that not a valid number ?
The godoc comment on the behavior of Decimal.rescale
:
// Rescale returns a rescaled version of the decimal. Returned
// decimal may be less precise if the given exponent is bigger
// than the initial exponent of the Decimal.
// NOTE: this will truncate, NOT round
//
// Example:
//
// d := New(12345, -4)
// d2 := d.rescale(-1)
// d3 := d2.rescale(-4)
// println(d1)
// println(d2)
// println(d3)
//
// Output:
//
// 1.2345
// 1.2
// 1.2000
//
indicates that the following test should pass:
func TestNegativeScale(t *testing.T) {
ref := New(12345, -4)
for _, testCase := range []struct {
d Decimal
s string
}{
{ref, "1.2345"},
{ref.rescale(-1), "1.2"},
{ref.rescale(-1).rescale(-4), "1.2000"},
} {
if testCase.d.String() != testCase.s {
t.Errorf("expected %q got %q", testCase.s, testCase.d.String())
}
}
}
However, Decimal.String
does not match this behavior. The third test case fails, as the zeroes to the right are dropped; you get "1.2".
In the case of representing currency amounts as a string, I'd want New(5, -2).String()
to give me "5.00" instead of "5"... or if String
isn't appropriate for this, then I need a StringXyz
method variant that retains zero placeholders for the full scale of the decimal.
I tried to do following and it outputs 11.199999
, I think the correct behaviour should be 11.200000
decimal.NewFromFloat(10.00000000).Add(decimal.NewFromFloat(1.20000000)).Truncate(6).Float64()
The culprit is here, around line 207:
if exp2 == 0 {
// specials
if mant == 0 {
return Decimal{} // <---- No. Just... no. Bad!
} else {
// subnormal
exp2++
}
....
This works ok up until the point you try to query the contents of the Decimal struct, say using .Coefficient() . It throws a nil pointer dereference panic (as .value is nil). This is problematic.
To fix, change the return to:
return Decimal{ value: big.NewInt(0), exp: 0 }
Also, probably worth adding the check to ensureInitialised() on all functions that might try and reference .value in some way
Testing: github.com/shopspring/decimal
Testing: "/builddir/build/BUILD/decimal-1.1.0/_build/src/github.com/shopspring/decimal"
+ GOPATH=/builddir/build/BUILD/decimal-1.1.0/_build:/usr/share/gocode
+ go test -buildmode pie -compiler gc -ldflags '-extldflags '\''-Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld '\'''
--- FAIL: TestFloat64 (0.00s)
decimal_test.go:297: 0.00000000000000000100000000000000000000000000000000012341234 should be represented inexactly
decimal_test.go:297: 0.00000000000000000299999999999999999999999900000000000123412341234 should be represented inexactly
decimal_test.go:297: -0.00000000000000000100000000000000000000000000000000012341234 should be represented inexactly
decimal_test.go:297: -0.00000000000000000299999999999999999999999900000000000123412341234 should be represented inexactly
FAIL
exit status 1
FAIL github.com/shopspring/decimal 32.706s
Hey there!
I saw this library featured in http://golangweekly.com/issues/49 and the first thing that occurred to me was why wouldn't you use the stdlib math/big
library. Would you please elucidate me on this one?
Here's the equivalent README example using math/big
.
package main
import (
"fmt"
"math/big"
)
func main() {
price, ok := new(big.Rat).SetString("136.02")
if !ok {
panic("parsing decimal failed")
}
quantity := new(big.Rat).SetFloat64(3)
fee, _ := new(big.Rat).SetString(".035")
taxRate, _ := new(big.Rat).SetString(".08875")
subtotal := new(big.Rat).Mul(price, quantity)
preTax := new(big.Rat).Mul(subtotal, new(big.Rat).Add(fee, new(big.Rat).SetFloat64(1)))
total := new(big.Rat).Mul(preTax, new(big.Rat).Add(taxRate, new(big.Rat).SetFloat64(1)))
fmt.Println("Subtotal:", subtotal.FloatString(9))
fmt.Println("Pre-tax:", preTax.FloatString(9))
fmt.Println("Taxes:", new(big.Rat).Sub(total, preTax).FloatString(9))
fmt.Println("Total:", total.FloatString(9))
fmt.Println("Tax rate:", new(big.Rat).Quo(new(big.Rat).Sub(total, preTax), preTax).FloatString(9))
}
Which outputs:
Subtotal: 408.060000000
Pre-tax: 422.342100000
Taxes: 37.482861375
Total: 459.824961375
Tax rate: 0.088750000
Long time listener, first time caller.
I couldn't see any documentation on this, so I thought I'd ask: is there a reason that support for JSON serialization to a specified number of decimal places isn't supported via a struct tag? I'm thinking something like:
type Foo struct {
Bar decimal.Decimal `json:"bar",decimalPlaces:"2"`
}
The advantage here being that if my API returns, e.g., a number corresponding to a dollar amount, it can be serialized as 5.20
rather than 5.2
This line wraps the string representation of a value into double quotes which get transferred "as is" into the resulting JSON representation.
While I understand that a package is free to pick any "on-the-wire" representation for the values of the types it works with, I would make a claim that the selected approach is incorrect: the JSON spec defines the representation for "numbers" -- which includes both "plain" integers and floating-point values in the scientific notation, and the Decimal
type provided by this package represents numbers, so I would expect it to serialize into JSON as numbers as well.
The rationale is that a receiving end for JSON representations serialized from Decimal
values handled by this package is not necessarily written using the same package (or even in Go), so it naturally expects to parse these representations to whatever numeric type it supports -- be it floats, Java's BigDecimal
, .NET's decimal
and so on. Currently we either rely on some sloppiness of the receiver's decoder (for instance, the Json.Net library is happy to parse whatever this package produces into decimal
s) or require custom unmarshaling.
Actually the inconsistency I'm talking about was caught by the testing code in one of my packages -- which tested JSON serialization of whatever stuff my package generates -- after I converted its parts which work with amounts of money to use Decimal
rather than stock float64
: floats were marshaled as numbers, and Decimal
s suddenly got double-quoted (while containing the same string representations as floats).
TL;DR
I think that Decimal
s should be marshaled to JSON as numbers, not as strings.
I'm currently working on an application that would benefit greatly from this lib, due to requirements with floating point precision. However benchmark tests of that application are worrying.
The scenario involves creating Decimal values, and then calling the various comparison methods on them. This sequence of events happens millions of times. Immediately after converting my code to use Decimal (instead of big.float, which was showing unacceptable precision loss after 20 significant digits), the performance time of our benchmark test went from 3-4 minutes for the test, to 22, on the same processor. pprof helped narrow the problem to the fact that your implementation of CMP involves the creation of an additional 2 decimal objects whenever the 'exp' values were different (which was pretty much every time), which is in line with the fact that after the change, 60% of the cpu time was spent allocating memory.
Is there a particular reason this approach was taken? Would a PR attempting to optimize this be accepted?
Hey all! Thanks for the really useful package.
I was wondering if you are open to starting to tag releases with semantic versions (e.g. v0.0.1). I've been refreshing my go knowledge and discovered the go dep
tool. It uses github tags for explicit version pins, and I'd love to pin a particular version of decimal instead of the master branch. Thanks! :)
Currently we have this
// Value implements the driver.Valuer interface for database serialisation.
func (d *Decimal) Value() (driver.Value, error) {
if d == nil {
return nil, nil
}
return d.String(), nil
}
while it's unclear how can it be that decimal is nil, and why should it be a function of a pointer at all?
https://github.com/jinzhu/gorm/issues/1250#issuecomment-259585820
Hey, thanks for this great library.
Would you like to support also Cash rounding? https://en.wikipedia.org/wiki/Cash_rounding
I can send in a PR. Let me know.
Hello,
I want to know how I can easily round up with decimal?
For example with roundup method that doesn't exist :
pi, _ := NewFromString("3.14159265359")
fmt.Println(pi.RoundUp(1)) // 3.2
Thank
Right now it's assumed that trailing zeros should be removed upon a call to Value
, as a decimal is being serialized into the database. This doesn't take into account cases where you want to keep the number of decimal places consistent across the board. For example, if I created a Decimal
via:
dec, _ := decimal.NewFromString("100.00")
I would expect it to enter the database as "100.00". When in actuality, the trailing zeros are removed and "100" is saved. This creates some interesting scenarios when storing and retrieving decimals from the database. I would expect the precedent to be that decimals are represented as a string in exactly the same way they were created, unless the user does an operation that would change the precision(such as using StringFixed
).
As it stands, Decimal does not work as map key. This is because it uses value *big.Int
. Why not just value big.Int
? Is there a real reason it is coded this way? Is this for performance? Have you measured this?
Shouldn't this struct below be empty when using the json marshaller? Since the go json docs state that 0 is considered an empty value. But because of the cast to string, all the struct fields show up.
package main
import (
"encoding/json"
"github.com/shopspring/decimal"
"fmt"
)
type Specs struct {
Watts decimal.Decimal `json:"watts,omitempty"`
Amps decimal.Decimal `json:"amps,omitempty"`
Voltage decimal.Decimal `json:"voltage,omitempty"`
}
func main() {
s := new(Specs)
res,err := json.Marshal(s)
if err != nil {
fmt.Printf("ERR: %s", err.Error())
return
}
fmt.Printf("SPECS: %s\n", res)
}
// outputs -> SPECS: {"watts":"0","amps":"0","voltage":"0"}
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
s := "13181.463"
f1, _ := decimal.NewFromString(s)
d := decimal.NewFromFloat(1000)
f2 := f1.Mul(d)
f3 := f1.Div(d)
f4 := f1.Mul(d).Div(d)
fmt.Println(f1, f1.Exponent(), f2, f2.Exponent(), f3, f3.Exponent(), f4, f4.Exponent())
}
output:
13181.463 -3 13181463 -3 13.181463 -16 13181.463 -16
f2.Exponent, f3.Exponent(), f4.Exponent() are all return a wrong result.
We just updated decimal
and it seems that the behaviour of decimal.NewFromFloat
was recently changed.
decimal.NewFromFloat(127.38)
will now return 127.3799999999999954525264911353588104248046875
, while it was expected to return 127.38
(ie. 12738
with exponent -2
).
I noticed in several places, you guys are panicking - with good intentions.
The problem is, this makes it a lot harder to "trust" the library will not cause problems when handed improper inputs.
The better solution to this is to return an error, which must be handled by the user expressly. While it's more code involved to work with the library, it's also a significantly safer approach to providing functionality for others to consume.
If this is a PR you'd accept, I would happily make this change.
Is there a reason that this package mostly deals in value types? It makes json-ifying things somewhat tricky in some cases. Consider the following:
type WireType struct {
Id int `"json:id"`
Num decimal.Decimal `json:"num,string,omitempty"`
}
When this struct is marshaled, it will never omit Num
, because json
doesn't know when Num
is zero.
The obvious fix for this is to make Num
a pointer type, but since this lib relies heavliy on non-mutable/value types, this turns otherwise nice-looking code:
params := WireType{1, decimal.NewFromFloat(1.0),}
factor := decimal.NewFromFloat(2.0).Mul(params.Num)
Into this (where num is of type *decimal.Decimal
):
one := decimal.NewFromFloat(1.0)
params := WireType{1, &one,}
factor := one.Mul(*params.Num)
Small potatoes? Maybe. But it would clean up the code a bit and make the API nicer in situations like this, especially in libraries which depend on decimal
, which then results in the end developer needing to always dereference Decimal
types in structs which depend on them.
Happy to work on a PR for this unless there are any fundamental objections.
NewFromFloat(9784.815).StringFixedBank(2) // output: "9784.82"
The result is wrong ,should be output: "9784.81"
decimal.NewFromFloat(0.357).Div(decimal.NewFromFloat(0.001)).Floor()
gives 356
and
x,_ := decimal.NewFromString("0.357")
y,_ := decimal.NewFromString("0.001")
x.Div(y).Floor()
gives 357
but the result should be consistent imho
When calculating taxes and converting between day/month/year bases, it is necessary to use Pow with decimal exponent. Is there any way to do this with this library?
When JSON data contains a null value for a Decimal field, the UnmarshalJSON function returns an error: Error decoding string 'null': can't convert null to decimal.
I am unsure if this is the intended behaviour. For Go native type float64, a null is set to 0.0 when unmarshaling. In this issue related to time.Time, the solution is to unmarshal null into the zero value.
To me, it makes sense to unmarshal null to the zero value of Decimal when the target variable is a struct. If the user wants to unmarshal to nil, she can still make the target variable a pointer:
type Example struct {
AsStruct decimal.Decimal
AsPointer *decimal.Decimal
}
var data = `{"AsStruct": null, "AsPointer"; null}`
var e Example
_ = json.Unmarshal(&e) // Ignoring error for this example. Actually, there would be no error returned.
fmt.Println("AsStruct", e.AsStruct, "AsPointer", e.AsPointer)
would produce
AsStruct 0 AsPointer nil
Have you considered having simpler constructors
NewFromInt(v) = New(int64(v), 0)
etc.?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.