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 }