gitee.com/quant1x/gox@v1.21.2/api/number.go (about)

     1  package api
     2  
     3  import (
     4  	"math"
     5  	"strconv"
     6  )
     7  
     8  const (
     9  	IGNORE_FLOAT = true
    10  )
    11  
    12  func ParseUint(s string) uint64 {
    13  	return parseUint64BestEffort(s)
    14  }
    15  
    16  func ParseInt(s string) int64 {
    17  	return parseInt64BestEffort(s)
    18  }
    19  
    20  func ParseFloat(s string) float64 {
    21  	return parseBestEffort(s)
    22  }
    23  
    24  // ParseUint64BestEffort parses uint64 number s.
    25  //
    26  // It is equivalent to strconv.ParseUint(s, 10, 64), but is faster.
    27  //
    28  // 0 is returned if the number cannot be parsed.
    29  func parseUint64BestEffort(s string) uint64 {
    30  	if len(s) == 0 {
    31  		return 0
    32  	}
    33  	i := uint(0)
    34  	d := uint64(0)
    35  	j := i
    36  	for i < uint(len(s)) {
    37  		if s[i] >= '0' && s[i] <= '9' {
    38  			d = d*10 + uint64(s[i]-'0')
    39  			i++
    40  			if i > 18 {
    41  				// The integer part may be out of range for uint64.
    42  				// Fall back to slow parsing.
    43  				dd, err := strconv.ParseUint(s, 10, 64)
    44  				if err != nil {
    45  					return 0
    46  				}
    47  				return dd
    48  			}
    49  			continue
    50  		}
    51  		break
    52  	}
    53  	if i <= j {
    54  		return 0
    55  	}
    56  	if !IGNORE_FLOAT && i < uint(len(s)) {
    57  		// Unparsed tail left.
    58  		return 0
    59  	}
    60  	return d
    61  }
    62  
    63  // ParseInt64BestEffort parses int64 number s.
    64  //
    65  // It is equivalent to strconv.ParseInt(s, 10, 64), but is faster.
    66  //
    67  // 0 is returned if the number cannot be parsed.
    68  func parseInt64BestEffort(s string) int64 {
    69  	if len(s) == 0 {
    70  		return 0
    71  	}
    72  	i := uint(0)
    73  	minus := s[0] == '-'
    74  	if minus {
    75  		i++
    76  		if i >= uint(len(s)) {
    77  			return 0
    78  		}
    79  	}
    80  
    81  	d := int64(0)
    82  	j := i
    83  	for i < uint(len(s)) {
    84  		if s[i] >= '0' && s[i] <= '9' {
    85  			d = d*10 + int64(s[i]-'0')
    86  			i++
    87  			if i > 18 {
    88  				// The integer part may be out of range for int64.
    89  				// Fall back to slow parsing.
    90  				dd, err := strconv.ParseInt(s, 10, 64)
    91  				if err != nil {
    92  					return 0
    93  				}
    94  				return dd
    95  			}
    96  			continue
    97  		}
    98  		break
    99  	}
   100  	if i <= j {
   101  		return 0
   102  	}
   103  	if !IGNORE_FLOAT && i < uint(len(s)) {
   104  		// Unparsed tail left.
   105  		return 0
   106  	}
   107  	if minus {
   108  		d = -d
   109  	}
   110  	return d
   111  }
   112  
   113  // ParseBestEffort parses floating-point number s.
   114  //
   115  // It is equivalent to strconv.ParseFloat(s, 64), but is faster.
   116  //
   117  // 0 is returned if the number cannot be parsed.
   118  func parseBestEffort(s string) float64 {
   119  	if len(s) == 0 {
   120  		return 0
   121  	}
   122  	i := uint(0)
   123  	minus := s[0] == '-'
   124  	if minus {
   125  		i++
   126  		if i >= uint(len(s)) {
   127  			return 0
   128  		}
   129  	}
   130  
   131  	d := uint64(0)
   132  	j := i
   133  	for i < uint(len(s)) {
   134  		if s[i] >= '0' && s[i] <= '9' {
   135  			d = d*10 + uint64(s[i]-'0')
   136  			i++
   137  			if i > 18 {
   138  				// The integer part may be out of range for uint64.
   139  				// Fall back to slow parsing.
   140  				f, err := strconv.ParseFloat(s, 64)
   141  				if err != nil && !math.IsInf(f, 0) {
   142  					return 0
   143  				}
   144  				return f
   145  			}
   146  			continue
   147  		}
   148  		break
   149  	}
   150  	if i <= j {
   151  		return 0
   152  	}
   153  	f := float64(d)
   154  	if i >= uint(len(s)) {
   155  		// Fast path - just integer.
   156  		if minus {
   157  			f = -f
   158  		}
   159  		return f
   160  	}
   161  
   162  	if s[i] == '.' {
   163  		// Parse fractional part.
   164  		i++
   165  		if i >= uint(len(s)) {
   166  			return 0
   167  		}
   168  		fr := uint64(0)
   169  		j := i
   170  		for i < uint(len(s)) {
   171  			if s[i] >= '0' && s[i] <= '9' {
   172  				fr = fr*10 + uint64(s[i]-'0')
   173  				i++
   174  				if i-j > 18 {
   175  					// The fractional part may be out of range for uint64.
   176  					// Fall back to standard parsing.
   177  					f, err := strconv.ParseFloat(s, 64)
   178  					if err != nil && !math.IsInf(f, 0) {
   179  						return 0
   180  					}
   181  					return f
   182  				}
   183  				continue
   184  			}
   185  			break
   186  		}
   187  		if i <= j {
   188  			return 0
   189  		}
   190  		f += float64(fr) / math.Pow10(int(i-j))
   191  		if i >= uint(len(s)) {
   192  			// Fast path - parsed fractional number.
   193  			if minus {
   194  				f = -f
   195  			}
   196  			return f
   197  		}
   198  	}
   199  	if s[i] == 'e' || s[i] == 'E' {
   200  		// Parse exponent part.
   201  		i++
   202  		if i >= uint(len(s)) {
   203  			return 0
   204  		}
   205  		expMinus := false
   206  		if s[i] == '+' || s[i] == '-' {
   207  			expMinus = s[i] == '-'
   208  			i++
   209  			if i >= uint(len(s)) {
   210  				return 0
   211  			}
   212  		}
   213  		exp := int16(0)
   214  		j := i
   215  		for i < uint(len(s)) {
   216  			if s[i] >= '0' && s[i] <= '9' {
   217  				exp = exp*10 + int16(s[i]-'0')
   218  				i++
   219  				if exp > 300 {
   220  					// The exponent may be too big for float64.
   221  					// Fall back to standard parsing.
   222  					f, err := strconv.ParseFloat(s, 64)
   223  					if err != nil && !math.IsInf(f, 0) {
   224  						return 0
   225  					}
   226  					return f
   227  				}
   228  				continue
   229  			}
   230  			break
   231  		}
   232  		if i <= j {
   233  			return 0
   234  		}
   235  		if expMinus {
   236  			exp = -exp
   237  		}
   238  		f *= math.Pow10(int(exp))
   239  		if i >= uint(len(s)) {
   240  			if minus {
   241  				f = -f
   242  			}
   243  			return f
   244  		}
   245  	}
   246  	return 0
   247  }