NewFromString returns a new Decimal from a string representation. Trailing zeroes are not trimmed. Example: d, err := NewFromString("-123.45") d2, err := NewFromString(".0001") d3, err := NewFromString("1.47000")
(value string)
| 178 | // d2, err := NewFromString(".0001") |
| 179 | // d3, err := NewFromString("1.47000") |
| 180 | func NewFromString(value string) (Decimal, error) { |
| 181 | originalInput := value |
| 182 | var intString string |
| 183 | var exp int64 |
| 184 | |
| 185 | // Check if number is using scientific notation |
| 186 | eIndex := strings.IndexAny(value, "Ee") |
| 187 | if eIndex != -1 { |
| 188 | expInt, err := strconv.ParseInt(value[eIndex+1:], 10, 32) |
| 189 | if err != nil { |
| 190 | if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { |
| 191 | return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", value) |
| 192 | } |
| 193 | return Decimal{}, fmt.Errorf("can't convert %s to decimal: exponent is not numeric", value) |
| 194 | } |
| 195 | value = value[:eIndex] |
| 196 | exp = expInt |
| 197 | } |
| 198 | |
| 199 | pIndex := -1 |
| 200 | vLen := len(value) |
| 201 | for i := 0; i < vLen; i++ { |
| 202 | if value[i] == '.' { |
| 203 | if pIndex > -1 { |
| 204 | return Decimal{}, fmt.Errorf("can't convert %s to decimal: too many .s", value) |
| 205 | } |
| 206 | pIndex = i |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | if pIndex == -1 { |
| 211 | // There is no decimal point, we can just parse the original string as |
| 212 | // an int |
| 213 | intString = value |
| 214 | } else { |
| 215 | if pIndex+1 < vLen { |
| 216 | intString = value[:pIndex] + value[pIndex+1:] |
| 217 | } else { |
| 218 | intString = value[:pIndex] |
| 219 | } |
| 220 | expInt := -len(value[pIndex+1:]) |
| 221 | exp += int64(expInt) |
| 222 | } |
| 223 | |
| 224 | var dValue *big.Int |
| 225 | // strconv.ParseInt is faster than new(big.Int).SetString so this is just a shortcut for strings we know won't overflow |
| 226 | if len(intString) <= 18 { |
| 227 | parsed64, err := strconv.ParseInt(intString, 10, 64) |
| 228 | if err != nil { |
| 229 | return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) |
| 230 | } |
| 231 | dValue = big.NewInt(parsed64) |
| 232 | } else { |
| 233 | dValue = new(big.Int) |
| 234 | _, ok := dValue.SetString(intString, 10) |
| 235 | if !ok { |
| 236 | return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) |
| 237 | } |
no outgoing calls
searching dependent graphs…