github.com/lianghucheng/zrddz@v0.0.0-20200923083010-c71f680932e2/src/gopkg.in/mgo.v2/bson/decimal.go (about)

     1  // BSON library for Go
     2  //
     3  // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
     4  //
     5  // All rights reserved.
     6  //
     7  // Redistribution and use in source and binary forms, with or without
     8  // modification, are permitted provided that the following conditions are met:
     9  //
    10  // 1. Redistributions of source code must retain the above copyright notice, this
    11  //    list of conditions and the following disclaimer.
    12  // 2. Redistributions in binary form must reproduce the above copyright notice,
    13  //    this list of conditions and the following disclaimer in the documentation
    14  //    and/or other materials provided with the distribution.
    15  //
    16  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    17  // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    18  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    19  // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    20  // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    21  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    22  // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    23  // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    24  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    25  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    26  
    27  package bson
    28  
    29  import (
    30  	"fmt"
    31  	"strconv"
    32  	"strings"
    33  )
    34  
    35  // Decimal128 holds decimal128 BSON values.
    36  type Decimal128 struct {
    37  	h, l uint64
    38  }
    39  
    40  func (d Decimal128) String() string {
    41  	var pos int     // positive sign
    42  	var e int       // exponent
    43  	var h, l uint64 // significand high/low
    44  
    45  	if d.h>>63&1 == 0 {
    46  		pos = 1
    47  	}
    48  
    49  	switch d.h >> 58 & (1<<5 - 1) {
    50  	case 0x1F:
    51  		return "NaN"
    52  	case 0x1E:
    53  		return "-Inf"[pos:]
    54  	}
    55  
    56  	l = d.l
    57  	if d.h>>61&3 == 3 {
    58  		// Bits: 1*sign 2*ignored 14*exponent 111*significand.
    59  		// Implicit 0b100 prefix in significand.
    60  		e = int(d.h>>47&(1<<14-1)) - 6176
    61  		//h = 4<<47 | d.h&(1<<47-1)
    62  		// Spec says all of these values are out of range.
    63  		h, l = 0, 0
    64  	} else {
    65  		// Bits: 1*sign 14*exponent 113*significand
    66  		e = int(d.h>>49&(1<<14-1)) - 6176
    67  		h = d.h & (1<<49 - 1)
    68  	}
    69  
    70  	// Would be handled by the logic below, but that's trivial and common.
    71  	if h == 0 && l == 0 && e == 0 {
    72  		return "-0"[pos:]
    73  	}
    74  
    75  	var repr [48]byte // Loop 5 times over 9 digits plus dot, negative sign, and leading zero.
    76  	var last = len(repr)
    77  	var i = len(repr)
    78  	var dot = len(repr) + e
    79  	var rem uint32
    80  Loop:
    81  	for d9 := 0; d9 < 5; d9++ {
    82  		h, l, rem = divmod(h, l, 1e9)
    83  		for d1 := 0; d1 < 9; d1++ {
    84  			// Handle "-0.0", "0.00123400", "-1.00E-6", "1.050E+3", etc.
    85  			if i < len(repr) && (dot == i || l == 0 && h == 0 && rem > 0 && rem < 10 && (dot < i-6 || e > 0)) {
    86  				e += len(repr) - i
    87  				i--
    88  				repr[i] = '.'
    89  				last = i - 1
    90  				dot = len(repr) // Unmark.
    91  			}
    92  			c := '0' + byte(rem%10)
    93  			rem /= 10
    94  			i--
    95  			repr[i] = c
    96  			// Handle "0E+3", "1E+3", etc.
    97  			if l == 0 && h == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || e > 0) {
    98  				last = i
    99  				break Loop
   100  			}
   101  			if c != '0' {
   102  				last = i
   103  			}
   104  			// Break early. Works without it, but why.
   105  			if dot > i && l == 0 && h == 0 && rem == 0 {
   106  				break Loop
   107  			}
   108  		}
   109  	}
   110  	repr[last-1] = '-'
   111  	last--
   112  
   113  	if e > 0 {
   114  		return string(repr[last+pos:]) + "E+" + strconv.Itoa(e)
   115  	}
   116  	if e < 0 {
   117  		return string(repr[last+pos:]) + "E" + strconv.Itoa(e)
   118  	}
   119  	return string(repr[last+pos:])
   120  }
   121  
   122  func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) {
   123  	div64 := uint64(div)
   124  	a := h >> 32
   125  	aq := a / div64
   126  	ar := a % div64
   127  	b := ar<<32 + h&(1<<32-1)
   128  	bq := b / div64
   129  	br := b % div64
   130  	c := br<<32 + l>>32
   131  	cq := c / div64
   132  	cr := c % div64
   133  	d := cr<<32 + l&(1<<32-1)
   134  	dq := d / div64
   135  	dr := d % div64
   136  	return (aq<<32 | bq), (cq<<32 | dq), uint32(dr)
   137  }
   138  
   139  var dNaN = Decimal128{0x1F << 58, 0}
   140  var dPosInf = Decimal128{0x1E << 58, 0}
   141  var dNegInf = Decimal128{0x3E << 58, 0}
   142  
   143  func dErr(s string) (Decimal128, error) {
   144  	return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s)
   145  }
   146  
   147  func ParseDecimal128(s string) (Decimal128, error) {
   148  	orig := s
   149  	if s == "" {
   150  		return dErr(orig)
   151  	}
   152  	neg := s[0] == '-'
   153  	if neg || s[0] == '+' {
   154  		s = s[1:]
   155  	}
   156  
   157  	if (len(s) == 3 || len(s) == 8) && (s[0] == 'N' || s[0] == 'n' || s[0] == 'I' || s[0] == 'i') {
   158  		if s == "NaN" || s == "nan" || strings.EqualFold(s, "nan") {
   159  			return dNaN, nil
   160  		}
   161  		if s == "Inf" || s == "inf" || strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") {
   162  			if neg {
   163  				return dNegInf, nil
   164  			}
   165  			return dPosInf, nil
   166  		}
   167  		return dErr(orig)
   168  	}
   169  
   170  	var h, l uint64
   171  	var e int
   172  
   173  	var add, ovr uint32
   174  	var mul uint32 = 1
   175  	var dot = -1
   176  	var digits = 0
   177  	var i = 0
   178  	for i < len(s) {
   179  		c := s[i]
   180  		if mul == 1e9 {
   181  			h, l, ovr = muladd(h, l, mul, add)
   182  			mul, add = 1, 0
   183  			if ovr > 0 || h&((1<<15-1)<<49) > 0 {
   184  				return dErr(orig)
   185  			}
   186  		}
   187  		if c >= '0' && c <= '9' {
   188  			i++
   189  			if c > '0' || digits > 0 {
   190  				digits++
   191  			}
   192  			if digits > 34 {
   193  				if c == '0' {
   194  					// Exact rounding.
   195  					e++
   196  					continue
   197  				}
   198  				return dErr(orig)
   199  			}
   200  			mul *= 10
   201  			add *= 10
   202  			add += uint32(c - '0')
   203  			continue
   204  		}
   205  		if c == '.' {
   206  			i++
   207  			if dot >= 0 || i == 1 && len(s) == 1 {
   208  				return dErr(orig)
   209  			}
   210  			if i == len(s) {
   211  				break
   212  			}
   213  			if s[i] < '0' || s[i] > '9' || e > 0 {
   214  				return dErr(orig)
   215  			}
   216  			dot = i
   217  			continue
   218  		}
   219  		break
   220  	}
   221  	if i == 0 {
   222  		return dErr(orig)
   223  	}
   224  	if mul > 1 {
   225  		h, l, ovr = muladd(h, l, mul, add)
   226  		if ovr > 0 || h&((1<<15-1)<<49) > 0 {
   227  			return dErr(orig)
   228  		}
   229  	}
   230  	if dot >= 0 {
   231  		e += dot - i
   232  	}
   233  	if i+1 < len(s) && (s[i] == 'E' || s[i] == 'e') {
   234  		i++
   235  		eneg := s[i] == '-'
   236  		if eneg || s[i] == '+' {
   237  			i++
   238  			if i == len(s) {
   239  				return dErr(orig)
   240  			}
   241  		}
   242  		n := 0
   243  		for i < len(s) && n < 1e4 {
   244  			c := s[i]
   245  			i++
   246  			if c < '0' || c > '9' {
   247  				return dErr(orig)
   248  			}
   249  			n *= 10
   250  			n += int(c - '0')
   251  		}
   252  		if eneg {
   253  			n = -n
   254  		}
   255  		e += n
   256  		for e < -6176 {
   257  			// Subnormal.
   258  			var div uint32 = 1
   259  			for div < 1e9 && e < -6176 {
   260  				div *= 10
   261  				e++
   262  			}
   263  			var rem uint32
   264  			h, l, rem = divmod(h, l, div)
   265  			if rem > 0 {
   266  				return dErr(orig)
   267  			}
   268  		}
   269  		for e > 6111 {
   270  			// Clamped.
   271  			var mul uint32 = 1
   272  			for mul < 1e9 && e > 6111 {
   273  				mul *= 10
   274  				e--
   275  			}
   276  			h, l, ovr = muladd(h, l, mul, 0)
   277  			if ovr > 0 || h&((1<<15-1)<<49) > 0 {
   278  				return dErr(orig)
   279  			}
   280  		}
   281  		if e < -6176 || e > 6111 {
   282  			return dErr(orig)
   283  		}
   284  	}
   285  
   286  	if i < len(s) {
   287  		return dErr(orig)
   288  	}
   289  
   290  	h |= uint64(e+6176) & uint64(1<<14-1) << 49
   291  	if neg {
   292  		h |= 1 << 63
   293  	}
   294  	return Decimal128{h, l}, nil
   295  }
   296  
   297  func muladd(h, l uint64, mul uint32, add uint32) (resh, resl uint64, overflow uint32) {
   298  	mul64 := uint64(mul)
   299  	a := mul64 * (l & (1<<32 - 1))
   300  	b := a>>32 + mul64*(l>>32)
   301  	c := b>>32 + mul64*(h&(1<<32-1))
   302  	d := c>>32 + mul64*(h>>32)
   303  
   304  	a = a&(1<<32-1) + uint64(add)
   305  	b = b&(1<<32-1) + a>>32
   306  	c = c&(1<<32-1) + b>>32
   307  	d = d&(1<<32-1) + c>>32
   308  
   309  	return (d<<32 | c&(1<<32-1)), (b<<32 | a&(1<<32-1)), uint32(d >> 32)
   310  }