github.com/cockroachdb/apd/v3@v3.2.0/decimal_test.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied. See the License for the specific language governing
    13  // permissions and limitations under the License.
    14  
    15  package apd
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"math"
    21  	"math/bits"
    22  	"testing"
    23  	"unsafe"
    24  )
    25  
    26  var (
    27  	testCtx = &BaseContext
    28  )
    29  
    30  func (d *Decimal) GoString() string {
    31  	return fmt.Sprintf(`{Coeff: %s, Exponent: %d, Negative: %v, Form: %s}`, d.Coeff.String(), d.Exponent, d.Negative, d.Form)
    32  }
    33  
    34  // testExponentError skips t if err was caused by an exponent being outside
    35  // of the package's supported exponent range. Since the exponent is so large,
    36  // we don't support those tests yet (i.e., it's an expected failure, so we
    37  // skip it).
    38  func testExponentError(t *testing.T, err error) {
    39  	if err == nil {
    40  		return
    41  	}
    42  	if err.Error() == errExponentOutOfRangeStr {
    43  		t.Skip(err)
    44  	}
    45  }
    46  
    47  func newDecimal(t *testing.T, c *Context, s string) *Decimal {
    48  	d, _, err := c.NewFromString(s)
    49  	testExponentError(t, err)
    50  	if err != nil {
    51  		t.Fatalf("%s: %+v", s, err)
    52  	}
    53  	return d
    54  }
    55  
    56  func TestNewWithBigInt(t *testing.T) {
    57  	tests := []string{
    58  		"0",
    59  		"1",
    60  		"-1",
    61  	}
    62  	for _, tc := range tests {
    63  		t.Run(tc, func(t *testing.T) {
    64  			expect, _, err := new(Decimal).SetString(tc)
    65  			if err != nil {
    66  				t.Fatal(err)
    67  			}
    68  			b, ok := new(BigInt).SetString(tc, 10)
    69  			if !ok {
    70  				t.Fatal("bad bigint")
    71  			}
    72  			d := NewWithBigInt(b, 0)
    73  			if d.Coeff.Sign() < 0 {
    74  				t.Fatal("unexpected negative coeff")
    75  			}
    76  			// Verify that changing b doesn't change d.
    77  			b.Set(NewBigInt(1234))
    78  			if d.CmpTotal(expect) != 0 {
    79  				t.Fatalf("expected %s, got %s", expect, d)
    80  			}
    81  		})
    82  	}
    83  }
    84  
    85  func TestUpscale(t *testing.T) {
    86  	tests := []struct {
    87  		x, y *Decimal
    88  		a, b *BigInt
    89  		s    int32
    90  	}{
    91  		{x: New(1, 0), y: New(100, -1), a: NewBigInt(10), b: NewBigInt(100), s: -1},
    92  		{x: New(1, 0), y: New(10, -1), a: NewBigInt(10), b: NewBigInt(10), s: -1},
    93  		{x: New(1, 0), y: New(10, 0), a: NewBigInt(1), b: NewBigInt(10), s: 0},
    94  		{x: New(1, 1), y: New(1, 0), a: NewBigInt(10), b: NewBigInt(1), s: 0},
    95  		{x: New(10, -2), y: New(1, -1), a: NewBigInt(10), b: NewBigInt(10), s: -2},
    96  		{x: New(1, -2), y: New(100, 1), a: NewBigInt(1), b: NewBigInt(100000), s: -2},
    97  	}
    98  	for _, tc := range tests {
    99  		t.Run(fmt.Sprintf("%s, %s", tc.x, tc.y), func(t *testing.T) {
   100  			a, b, s, err := upscale(tc.x, tc.y, new(BigInt))
   101  			if err != nil {
   102  				t.Fatal(err)
   103  			}
   104  			if a.Cmp(tc.a) != 0 {
   105  				t.Errorf("a: expected %s, got %s", tc.a, a)
   106  			}
   107  			if b.Cmp(tc.b) != 0 {
   108  				t.Errorf("b: expected %s, got %s", tc.b, b)
   109  			}
   110  			if s != tc.s {
   111  				t.Errorf("s: expected %d, got %d", tc.s, s)
   112  			}
   113  		})
   114  	}
   115  }
   116  
   117  func TestAdd(t *testing.T) {
   118  	tests := []struct {
   119  		x, y string
   120  		r    string
   121  	}{
   122  		{x: "1", y: "10", r: "11"},
   123  		{x: "1", y: "1e1", r: "11"},
   124  		{x: "1e1", y: "1", r: "11"},
   125  		{x: ".1e1", y: "100e-1", r: "11.0"},
   126  	}
   127  	for _, tc := range tests {
   128  		t.Run(fmt.Sprintf("%s, %s", tc.x, tc.y), func(t *testing.T) {
   129  			x := newDecimal(t, testCtx, tc.x)
   130  			y := newDecimal(t, testCtx, tc.y)
   131  			d := new(Decimal)
   132  			_, err := testCtx.Add(d, x, y)
   133  			if err != nil {
   134  				t.Fatal(err)
   135  			}
   136  			s := d.String()
   137  			if s != tc.r {
   138  				t.Fatalf("expected: %s, got: %s", tc.r, s)
   139  			}
   140  		})
   141  	}
   142  }
   143  
   144  func TestCmp(t *testing.T) {
   145  	tests := []struct {
   146  		x, y string
   147  		c    int
   148  	}{
   149  		{x: "1", y: "10", c: -1},
   150  		{x: "1", y: "1e1", c: -1},
   151  		{x: "1e1", y: "1", c: 1},
   152  		{x: ".1e1", y: "100e-1", c: -1},
   153  
   154  		{x: ".1e1", y: "100e-2", c: 0},
   155  		{x: "1", y: ".1e1", c: 0},
   156  		{x: "1", y: "1", c: 0},
   157  	}
   158  	for _, tc := range tests {
   159  		t.Run(fmt.Sprintf("%s, %s", tc.x, tc.y), func(t *testing.T) {
   160  			x := newDecimal(t, testCtx, tc.x)
   161  			y := newDecimal(t, testCtx, tc.y)
   162  			c := x.Cmp(y)
   163  			if c != tc.c {
   164  				t.Fatalf("expected: %d, got: %d", tc.c, c)
   165  			}
   166  		})
   167  	}
   168  }
   169  
   170  func TestModf(t *testing.T) {
   171  	tests := []struct {
   172  		x string
   173  		i string
   174  		f string
   175  	}{
   176  		{x: "1", i: "1", f: "0"},
   177  		{x: "1.0", i: "1", f: "0.0"},
   178  		{x: "1.0e1", i: "10", f: "0"},
   179  		{x: "1.0e2", i: "1.0E+2", f: "0"},
   180  		{x: "1.0e-1", i: "0", f: "0.10"},
   181  		{x: "1.0e-2", i: "0", f: "0.010"},
   182  		{x: "1.1", i: "1", f: "0.1"},
   183  		{x: "1234.56", i: "1234", f: "0.56"},
   184  		{x: "1234.56e2", i: "123456", f: "0"},
   185  		{x: "1234.56e4", i: "1.23456E+7", f: "0"},
   186  		{x: "1234.56e-2", i: "12", f: "0.3456"},
   187  		{x: "1234.56e-4", i: "0", f: "0.123456"},
   188  		{x: "1234.56e-6", i: "0", f: "0.00123456"},
   189  		{x: "123456e-8", i: "0", f: "0.00123456"},
   190  		{x: ".123456e8", i: "1.23456E+7", f: "0"},
   191  
   192  		{x: "-1", i: "-1", f: "-0"},
   193  		{x: "-1.0", i: "-1", f: "-0.0"},
   194  		{x: "-1.0e1", i: "-10", f: "-0"},
   195  		{x: "-1.0e2", i: "-1.0E+2", f: "-0"},
   196  		{x: "-1.0e-1", i: "-0", f: "-0.10"},
   197  		{x: "-1.0e-2", i: "-0", f: "-0.010"},
   198  		{x: "-1.1", i: "-1", f: "-0.1"},
   199  		{x: "-1234.56", i: "-1234", f: "-0.56"},
   200  		{x: "-1234.56e2", i: "-123456", f: "-0"},
   201  		{x: "-1234.56e4", i: "-1.23456E+7", f: "-0"},
   202  		{x: "-1234.56e-2", i: "-12", f: "-0.3456"},
   203  		{x: "-1234.56e-4", i: "-0", f: "-0.123456"},
   204  		{x: "-1234.56e-6", i: "-0", f: "-0.00123456"},
   205  		{x: "-123456e-8", i: "-0", f: "-0.00123456"},
   206  		{x: "-.123456e8", i: "-1.23456E+7", f: "-0"},
   207  	}
   208  	for _, tc := range tests {
   209  		t.Run(tc.x, func(t *testing.T) {
   210  			x := newDecimal(t, testCtx, tc.x)
   211  			integ, frac := new(Decimal), new(Decimal)
   212  			x.Modf(integ, frac)
   213  			if tc.i != integ.String() {
   214  				t.Fatalf("integ: expected: %s, got: %s", tc.i, integ)
   215  			}
   216  			if tc.f != frac.String() {
   217  				t.Fatalf("frac: expected: %s, got: %s", tc.f, frac)
   218  			}
   219  			a := new(Decimal)
   220  			if _, err := testCtx.Add(a, integ, frac); err != nil {
   221  				t.Fatal(err)
   222  			}
   223  			if a.Cmp(x) != 0 {
   224  				t.Fatalf("%s != %s", a, x)
   225  			}
   226  			if integ.Exponent < 0 {
   227  				t.Fatal(integ.Exponent)
   228  			}
   229  			if frac.Exponent > 0 {
   230  				t.Fatal(frac.Exponent)
   231  			}
   232  
   233  			integ2, frac2 := new(Decimal), new(Decimal)
   234  			x.Modf(integ2, nil)
   235  			x.Modf(nil, frac2)
   236  			if integ.CmpTotal(integ2) != 0 {
   237  				t.Fatalf("got %s, expected %s", integ2, integ)
   238  			}
   239  			if frac.CmpTotal(frac2) != 0 {
   240  				t.Fatalf("got %s, expected %s", frac2, frac)
   241  			}
   242  		})
   243  	}
   244  
   245  	// Ensure we don't panic on both nil.
   246  	a := new(Decimal)
   247  	a.Modf(nil, nil)
   248  }
   249  
   250  func TestInt64(t *testing.T) {
   251  	tests := []struct {
   252  		x   string
   253  		i   int64
   254  		err bool
   255  	}{
   256  		{x: "0.12e1", err: true},
   257  		{x: "0.1e1", i: 1},
   258  		{x: "10", i: 10},
   259  		{x: "12.3e3", i: 12300},
   260  		{x: "1e-1", err: true},
   261  		{x: "1e2", i: 100},
   262  		{x: "1", i: 1},
   263  		{x: "NaN", err: true},
   264  		{x: "Inf", err: true},
   265  		{x: "9223372036854775807", i: 9223372036854775807},
   266  		{x: "-9223372036854775808", i: -9223372036854775808},
   267  		{x: "9223372036854775808", err: true},
   268  	}
   269  	for _, tc := range tests {
   270  		t.Run(tc.x, func(t *testing.T) {
   271  			x := newDecimal(t, testCtx, tc.x)
   272  			i, err := x.Int64()
   273  			hasErr := err != nil
   274  			if tc.err != hasErr {
   275  				t.Fatalf("expected error: %v, got error: %v", tc.err, err)
   276  			}
   277  			if hasErr {
   278  				return
   279  			}
   280  			if i != tc.i {
   281  				t.Fatalf("expected: %v, got %v", tc.i, i)
   282  			}
   283  		})
   284  	}
   285  }
   286  
   287  func TestQuoErr(t *testing.T) {
   288  	tests := []struct {
   289  		x, y string
   290  		p    uint32
   291  		err  string
   292  	}{
   293  		{x: "1", y: "1", p: 0, err: errZeroPrecisionStr},
   294  		{x: "1", y: "0", p: 1, err: "division by zero"},
   295  	}
   296  	for _, tc := range tests {
   297  		c := testCtx.WithPrecision(tc.p)
   298  		x := newDecimal(t, testCtx, tc.x)
   299  		y := newDecimal(t, testCtx, tc.y)
   300  		d := new(Decimal)
   301  		_, err := c.Quo(d, x, y)
   302  		if err == nil {
   303  			t.Fatal("expected error")
   304  		}
   305  		if err.Error() != tc.err {
   306  			t.Fatalf("expected %s, got %s", tc.err, err)
   307  		}
   308  	}
   309  }
   310  
   311  func TestConditionString(t *testing.T) {
   312  	tests := map[Condition]string{
   313  		Overflow:             "overflow",
   314  		Overflow | Underflow: "overflow, underflow",
   315  		Subnormal | Inexact:  "inexact, subnormal",
   316  	}
   317  	for c, s := range tests {
   318  		t.Run(s, func(t *testing.T) {
   319  			cs := c.String()
   320  			if cs != s {
   321  				t.Errorf("expected %s; got %s", s, cs)
   322  			}
   323  		})
   324  	}
   325  }
   326  
   327  func TestFloat64(t *testing.T) {
   328  	tests := []float64{
   329  		0,
   330  		1,
   331  		-1,
   332  		math.MaxFloat32,
   333  		math.SmallestNonzeroFloat32,
   334  		math.MaxFloat64,
   335  		math.SmallestNonzeroFloat64,
   336  	}
   337  
   338  	for _, tc := range tests {
   339  		t.Run(fmt.Sprint(tc), func(t *testing.T) {
   340  			d := new(Decimal)
   341  			d.SetFloat64(tc)
   342  			f, err := d.Float64()
   343  			if err != nil {
   344  				t.Fatal(err)
   345  			}
   346  			if tc != f {
   347  				t.Fatalf("expected %v, got %v", tc, f)
   348  			}
   349  		})
   350  	}
   351  }
   352  
   353  func TestCeil(t *testing.T) {
   354  	tests := map[float64]int64{
   355  		0:    0,
   356  		-0.1: 0,
   357  		0.1:  1,
   358  		-0.9: 0,
   359  		0.9:  1,
   360  		-1:   -1,
   361  		1:    1,
   362  		-1.1: -1,
   363  		1.1:  2,
   364  	}
   365  
   366  	for f, r := range tests {
   367  		t.Run(fmt.Sprint(f), func(t *testing.T) {
   368  			d, err := new(Decimal).SetFloat64(f)
   369  			if err != nil {
   370  				t.Fatal(err)
   371  			}
   372  			_, err = testCtx.Ceil(d, d)
   373  			if err != nil {
   374  				t.Fatal(err)
   375  			}
   376  			i, err := d.Int64()
   377  			if err != nil {
   378  				t.Fatal(err)
   379  			}
   380  			if i != r {
   381  				t.Fatalf("got %v, expected %v", i, r)
   382  			}
   383  		})
   384  	}
   385  }
   386  
   387  func TestFloor(t *testing.T) {
   388  	tests := map[float64]int64{
   389  		0:    0,
   390  		-0.1: -1,
   391  		0.1:  0,
   392  		-0.9: -1,
   393  		0.9:  0,
   394  		-1:   -1,
   395  		1:    1,
   396  		-1.1: -2,
   397  		1.1:  1,
   398  	}
   399  
   400  	for f, r := range tests {
   401  		t.Run(fmt.Sprint(f), func(t *testing.T) {
   402  			d, err := new(Decimal).SetFloat64(f)
   403  			if err != nil {
   404  				t.Fatal(err)
   405  			}
   406  			_, err = testCtx.Floor(d, d)
   407  			if err != nil {
   408  				t.Fatal(err)
   409  			}
   410  			i, err := d.Int64()
   411  			if err != nil {
   412  				t.Fatal(err)
   413  			}
   414  			if i != r {
   415  				t.Fatalf("got %v, expected %v", i, r)
   416  			}
   417  		})
   418  	}
   419  }
   420  
   421  func TestFormat(t *testing.T) {
   422  	tests := map[string]struct {
   423  		e, E, f, g, G string
   424  	}{
   425  		"NaN":       {},
   426  		"Infinity":  {},
   427  		"-Infinity": {},
   428  		"sNaN":      {},
   429  		"0": {
   430  			e: "0e+0",
   431  			E: "0E+0",
   432  		},
   433  		"-0": {
   434  			e: "-0e+0",
   435  			E: "-0E+0",
   436  		},
   437  		"0.0": {
   438  			e: "0e-1",
   439  			E: "0E-1",
   440  		},
   441  		"-0.0": {
   442  			e: "-0e-1",
   443  			E: "-0E-1",
   444  		},
   445  		"0E+2": {
   446  			e: "0e+2",
   447  			f: "000",
   448  			g: "0e+2",
   449  		},
   450  		"0E-9": {
   451  			e: "0e-9",
   452  			f: "0.000000000",
   453  			g: "0.000000000",
   454  			G: "0.000000000",
   455  		},
   456  	}
   457  	verbs := []string{"%e", "%E", "%f", "%g", "%G"}
   458  
   459  	for input, tc := range tests {
   460  		t.Run(input, func(t *testing.T) {
   461  			d, _, err := NewFromString(input)
   462  			if err != nil {
   463  				t.Fatal(err)
   464  			}
   465  			for i, s := range []string{tc.e, tc.E, tc.f, tc.g, tc.G} {
   466  				if s == "" {
   467  					s = input
   468  				}
   469  				v := verbs[i]
   470  				t.Run(v, func(t *testing.T) {
   471  					out := fmt.Sprintf(v, d)
   472  					if out != s {
   473  						t.Fatalf("expected %s, got %s", s, out)
   474  					}
   475  				})
   476  			}
   477  		})
   478  	}
   479  }
   480  
   481  func TestFormatFlags(t *testing.T) {
   482  	const stdD = "1.23E+56"
   483  	tests := []struct {
   484  		d   string
   485  		fmt string
   486  		out string
   487  	}{
   488  		{
   489  			d:   stdD,
   490  			fmt: "%3G",
   491  			out: "1.23E+56",
   492  		},
   493  		{
   494  			d:   stdD,
   495  			fmt: "%010G",
   496  			out: "001.23E+56",
   497  		},
   498  		{
   499  			d:   stdD,
   500  			fmt: "%10G",
   501  			out: "  1.23E+56",
   502  		},
   503  		{
   504  			d:   stdD,
   505  			fmt: "%+G",
   506  			out: "+1.23E+56",
   507  		},
   508  		{
   509  			d:   stdD,
   510  			fmt: "% G",
   511  			out: " 1.23E+56",
   512  		},
   513  		{
   514  			d:   stdD,
   515  			fmt: "%-10G",
   516  			out: "1.23E+56  ",
   517  		},
   518  		{
   519  			d:   stdD,
   520  			fmt: "%-010G",
   521  			out: "1.23E+56  ",
   522  		},
   523  		{
   524  			d:   "nan",
   525  			fmt: "%-10G",
   526  			out: "NaN       ",
   527  		},
   528  		{
   529  			d:   "nan",
   530  			fmt: "%10G",
   531  			out: "       NaN",
   532  		},
   533  		{
   534  			d:   "nan",
   535  			fmt: "%010G",
   536  			out: "       NaN",
   537  		},
   538  		{
   539  			d:   "inf",
   540  			fmt: "%-10G",
   541  			out: "Infinity  ",
   542  		},
   543  		{
   544  			d:   "inf",
   545  			fmt: "%10G",
   546  			out: "  Infinity",
   547  		},
   548  		{
   549  			d:   "inf",
   550  			fmt: "%010G",
   551  			out: "  Infinity",
   552  		},
   553  		{
   554  			d:   "-inf",
   555  			fmt: "%-10G",
   556  			out: "-Infinity ",
   557  		},
   558  		{
   559  			d:   "-inf",
   560  			fmt: "%10G",
   561  			out: " -Infinity",
   562  		},
   563  		{
   564  			d:   "-inf",
   565  			fmt: "%010G",
   566  			out: " -Infinity",
   567  		},
   568  		{
   569  			d:   "0",
   570  			fmt: "%d",
   571  			out: "%!d(*apd.Decimal=0)",
   572  		},
   573  	}
   574  	for _, tc := range tests {
   575  		t.Run(fmt.Sprintf("%s: %s", tc.d, tc.fmt), func(t *testing.T) {
   576  			d := newDecimal(t, &BaseContext, tc.d)
   577  			s := fmt.Sprintf(tc.fmt, d)
   578  			if s != tc.out {
   579  				t.Fatalf("expected %q, got %q", tc.out, s)
   580  			}
   581  		})
   582  	}
   583  }
   584  
   585  func TestContextSetStringt(t *testing.T) {
   586  	tests := []struct {
   587  		s      string
   588  		c      *Context
   589  		expect string
   590  	}{
   591  		{
   592  			s:      "1.234",
   593  			c:      &BaseContext,
   594  			expect: "1.234",
   595  		},
   596  		{
   597  			s:      "1.234",
   598  			c:      BaseContext.WithPrecision(2),
   599  			expect: "1.2",
   600  		},
   601  	}
   602  	for i, tc := range tests {
   603  		t.Run(fmt.Sprintf("%d: %s", i, tc.s), func(t *testing.T) {
   604  			d := new(Decimal)
   605  			if _, _, err := tc.c.SetString(d, tc.s); err != nil {
   606  				t.Fatal(err)
   607  			}
   608  			got := d.String()
   609  			if got != tc.expect {
   610  				t.Fatalf("expected: %s, got: %s", tc.expect, got)
   611  			}
   612  		})
   613  	}
   614  }
   615  
   616  func TestQuantize(t *testing.T) {
   617  	tests := []struct {
   618  		s      string
   619  		e      int32
   620  		expect string
   621  	}{
   622  		{
   623  			s:      "1.00",
   624  			e:      -1,
   625  			expect: "1.0",
   626  		},
   627  		{
   628  			s:      "2.0",
   629  			e:      -1,
   630  			expect: "2.0",
   631  		},
   632  		{
   633  			s:      "3",
   634  			e:      -1,
   635  			expect: "3.0",
   636  		},
   637  		{
   638  			s:      "9.9999",
   639  			e:      -2,
   640  			expect: "10.00",
   641  		},
   642  	}
   643  	c := BaseContext.WithPrecision(10)
   644  	for _, tc := range tests {
   645  		t.Run(fmt.Sprintf("%s: %d", tc.s, tc.e), func(t *testing.T) {
   646  			d, _, err := NewFromString(tc.s)
   647  			if err != nil {
   648  				t.Fatal(err)
   649  			}
   650  			if _, err := c.Quantize(d, d, tc.e); err != nil {
   651  				t.Fatal(err)
   652  			}
   653  			s := d.String()
   654  			if s != tc.expect {
   655  				t.Fatalf("expected: %s, got: %s", tc.expect, s)
   656  			}
   657  		})
   658  	}
   659  }
   660  
   661  func TestCmpOrder(t *testing.T) {
   662  	tests := []struct {
   663  		s     string
   664  		order int
   665  	}{
   666  		{s: "-NaN", order: -4},
   667  		{s: "-sNaN", order: -3},
   668  		{s: "-Infinity", order: -2},
   669  		{s: "-127", order: -1},
   670  		{s: "-1.00", order: -1},
   671  		{s: "-1", order: -1},
   672  		{s: "-0.000", order: -1},
   673  		{s: "-0", order: -1},
   674  		{s: "0", order: 1},
   675  		{s: "1.2300", order: 1},
   676  		{s: "1.23", order: 1},
   677  		{s: "1E+9", order: 1},
   678  		{s: "Infinity", order: 2},
   679  		{s: "sNaN", order: 3},
   680  		{s: "NaN", order: 4},
   681  	}
   682  
   683  	for _, tc := range tests {
   684  		t.Run(tc.s, func(t *testing.T) {
   685  			d, _, err := NewFromString(tc.s)
   686  			if err != nil {
   687  				t.Fatal(err)
   688  			}
   689  			o := d.cmpOrder()
   690  			if o != tc.order {
   691  				t.Fatalf("got %d, expected %d", o, tc.order)
   692  			}
   693  		})
   694  	}
   695  }
   696  
   697  func TestIsZero(t *testing.T) {
   698  	tests := []struct {
   699  		s    string
   700  		zero bool
   701  	}{
   702  		{s: "-NaN", zero: false},
   703  		{s: "-sNaN", zero: false},
   704  		{s: "-Infinity", zero: false},
   705  		{s: "-127", zero: false},
   706  		{s: "-1.00", zero: false},
   707  		{s: "-1", zero: false},
   708  		{s: "-0.000", zero: true},
   709  		{s: "-0", zero: true},
   710  		{s: "0", zero: true},
   711  		{s: "1.2300", zero: false},
   712  		{s: "1.23", zero: false},
   713  		{s: "1E+9", zero: false},
   714  		{s: "Infinity", zero: false},
   715  		{s: "sNaN", zero: false},
   716  		{s: "NaN", zero: false},
   717  	}
   718  
   719  	for _, tc := range tests {
   720  		t.Run(tc.s, func(t *testing.T) {
   721  			d, _, err := NewFromString(tc.s)
   722  			if err != nil {
   723  				t.Fatal(err)
   724  			}
   725  			z := d.IsZero()
   726  			if z != tc.zero {
   727  				t.Fatalf("got %v, expected %v", z, tc.zero)
   728  			}
   729  		})
   730  	}
   731  }
   732  
   733  func TestNeg(t *testing.T) {
   734  	tests := map[string]string{
   735  		"0":          "0",
   736  		"-0":         "0",
   737  		"-0.000":     "0.000",
   738  		"-00.000100": "0.000100",
   739  	}
   740  
   741  	for tc, expect := range tests {
   742  		t.Run(tc, func(t *testing.T) {
   743  			d, _, err := NewFromString(tc)
   744  			if err != nil {
   745  				t.Fatal(err)
   746  			}
   747  			var z Decimal
   748  			z.Neg(d)
   749  			s := z.String()
   750  			if s != expect {
   751  				t.Fatalf("expected %s, got %s", expect, s)
   752  			}
   753  		})
   754  	}
   755  }
   756  
   757  func TestReduce(t *testing.T) {
   758  	tests := map[string]int{
   759  		"-0":        0,
   760  		"0":         0,
   761  		"0.0":       0,
   762  		"00":        0,
   763  		"0.00":      0,
   764  		"-01000":    3,
   765  		"01000":     3,
   766  		"-1":        0,
   767  		"1":         0,
   768  		"-10.000E4": 4,
   769  		"10.000E4":  4,
   770  		"-10.00":    3,
   771  		"10.00":     3,
   772  		"-10":       1,
   773  		"10":        1,
   774  		"-143200000000000000000000000000000000000000000000000000000000": 56,
   775  		"143200000000000000000000000000000000000000000000000000000000":  56,
   776  		"Inf": 0,
   777  		"NaN": 0,
   778  	}
   779  
   780  	for s, n := range tests {
   781  		t.Run(s, func(t *testing.T) {
   782  			d, _, err := NewFromString(s)
   783  			if err != nil {
   784  				t.Fatal(err)
   785  			}
   786  			_, got := d.Reduce(d)
   787  			if n != got {
   788  				t.Fatalf("got %v, expected %v", got, n)
   789  			}
   790  		})
   791  	}
   792  }
   793  
   794  // TestSizeof is meant to catch changes that unexpectedly increase
   795  // the size of the BigInt, Decimal, and Context structs.
   796  func TestSizeof(t *testing.T) {
   797  	// map[uint_size][type]sizeof
   798  	exp := map[int]map[string]uintptr{
   799  		32: {
   800  			"BigInt":  20,
   801  			"Decimal": 28,
   802  			"Context": 24,
   803  		},
   804  		64: {
   805  			"BigInt":  24,
   806  			"Decimal": 32,
   807  			"Context": 32,
   808  		},
   809  	}[bits.UintSize]
   810  
   811  	var b BigInt
   812  	if s := unsafe.Sizeof(b); s != exp["BigInt"] {
   813  		t.Errorf("sizeof(BigInt) changed: %d", s)
   814  	}
   815  	var d Decimal
   816  	if s := unsafe.Sizeof(d); s != exp["Decimal"] {
   817  		t.Errorf("sizeof(Decimal) changed: %d", s)
   818  	}
   819  	var c Context
   820  	if s := unsafe.Sizeof(c); s != exp["Context"] {
   821  		t.Errorf("sizeof(Context) changed: %d", s)
   822  	}
   823  }
   824  
   825  // TestSize tests the Size method on BigInt and Decimal. Unlike Sizeof, which
   826  // returns the shallow size of the structs, the Size method reports the total
   827  // memory footprint of each struct and all referenced objects.
   828  func TestSize(t *testing.T) {
   829  	// map[uint_size][is_inline][type]size
   830  	exp := map[int]map[bool]map[string]uintptr{
   831  		32: {
   832  			true: {
   833  				"BigInt":  20,
   834  				"Decimal": 28,
   835  			},
   836  			false: {
   837  				"BigInt":  72,
   838  				"Decimal": 80,
   839  			},
   840  		},
   841  		64: {
   842  			true: {
   843  				"BigInt":  24,
   844  				"Decimal": 32,
   845  			},
   846  			false: {
   847  				"BigInt":  112,
   848  				"Decimal": 120,
   849  			},
   850  		},
   851  	}[bits.UintSize]
   852  
   853  	var d Decimal
   854  	if e, s := exp[true]["Decimal"], d.Size(); e != s {
   855  		t.Errorf("(*Decimal).Size() != %d: %d", e, s)
   856  	}
   857  	if e, s := exp[true]["BigInt"], d.Coeff.Size(); e != s {
   858  		t.Errorf("(*BigInt).Size() != %d: %d", e, s)
   859  	}
   860  	// Set to an inlinable value.
   861  	d.SetInt64(1234)
   862  	if e, s := exp[true]["Decimal"], d.Size(); e != s {
   863  		t.Errorf("(*Decimal).Size() != %d: %d", e, s)
   864  	}
   865  	if e, s := exp[true]["BigInt"], d.Coeff.Size(); e != s {
   866  		t.Errorf("(*BigInt).Size() != %d: %d", e, s)
   867  	}
   868  	// Set to a non-inlinable value.
   869  	if _, _, err := d.SetString("123456789123456789123456789.123456789123456789"); err != nil {
   870  		t.Fatal(err)
   871  	}
   872  	if d.Coeff.isInline() {
   873  		// Sanity-check, in case inlineWords changes.
   874  		t.Fatal("BigInt inlined large value. Did inlineWords change?")
   875  	}
   876  	if e, s := exp[false]["Decimal"], d.Size(); e != s {
   877  		t.Errorf("(*Decimal).Size() != %d: %d", e, s)
   878  	}
   879  	if e, s := exp[false]["BigInt"], d.Coeff.Size(); e != s {
   880  		t.Errorf("(*BigInt).Size() != %d: %d", e, s)
   881  	}
   882  }
   883  
   884  func TestJSONEncoding(t *testing.T) {
   885  	var encodingTests = []string{
   886  		"0",
   887  		"1",
   888  		"2",
   889  		"10",
   890  		"1000",
   891  		"1234567890",
   892  		"298472983472983471903246121093472394872319615612417471234712061",
   893  		"0.0",
   894  		"NaN",
   895  		"Inf",
   896  		"123.456",
   897  		"1E1",
   898  		"1E-1",
   899  		"1.2E3",
   900  	}
   901  
   902  	for _, test := range encodingTests {
   903  		for _, sign := range []string{"", "+", "-"} {
   904  			x := sign + test
   905  			var tx Decimal
   906  			tx.SetString(x)
   907  			b, err := json.Marshal(&tx)
   908  			if err != nil {
   909  				t.Errorf("marshaling of %s failed: %s", &tx, err)
   910  				continue
   911  			}
   912  			var rx Decimal
   913  			if err := json.Unmarshal(b, &rx); err != nil {
   914  				t.Errorf("unmarshaling of %s failed: %s", &tx, err)
   915  				continue
   916  			}
   917  			if rx.CmpTotal(&tx) != 0 {
   918  				t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
   919  			}
   920  		}
   921  	}
   922  }