diff options
Diffstat (limited to 'src/strconv/atoc.go')
-rw-r--r-- | src/strconv/atoc.go | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/strconv/atoc.go b/src/strconv/atoc.go new file mode 100644 index 0000000..85c7baf --- /dev/null +++ b/src/strconv/atoc.go @@ -0,0 +1,105 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +const fnParseComplex = "ParseComplex" + +// convErr splits an error returned by parseFloatPrefix +// into a syntax or range error for ParseComplex. +func convErr(err error, s string) (syntax, range_ error) { + if x, ok := err.(*NumError); ok { + x.Func = fnParseComplex + x.Num = s + if x.Err == ErrRange { + return nil, x + } + } + return err, nil +} + +// ParseComplex converts the string s to a complex number +// with the precision specified by bitSize: 64 for complex64, or 128 for complex128. +// When bitSize=64, the result still has type complex128, but it will be +// convertible to complex64 without changing its value. +// +// The number represented by s must be of the form N, Ni, or N±Ni, where N stands +// for a floating-point number as recognized by ParseFloat, and i is the imaginary +// component. If the second N is unsigned, a + sign is required between the two components +// as indicated by the ±. If the second N is NaN, only a + sign is accepted. +// The form may be parenthesized and cannot contain any spaces. +// The resulting complex number consists of the two components converted by ParseFloat. +// +// The errors that ParseComplex returns have concrete type *NumError +// and include err.Num = s. +// +// If s is not syntactically well-formed, ParseComplex returns err.Err = ErrSyntax. +// +// If s is syntactically well-formed but either component is more than 1/2 ULP +// away from the largest floating point number of the given component's size, +// ParseComplex returns err.Err = ErrRange and c = ±Inf for the respective component. +func ParseComplex(s string, bitSize int) (complex128, error) { + size := 64 + if bitSize == 64 { + size = 32 // complex64 uses float32 parts + } + + orig := s + + // Remove parentheses, if any. + if len(s) >= 2 && s[0] == '(' && s[len(s)-1] == ')' { + s = s[1 : len(s)-1] + } + + var pending error // pending range error, or nil + + // Read real part (possibly imaginary part if followed by 'i'). + re, n, err := parseFloatPrefix(s, size) + if err != nil { + err, pending = convErr(err, orig) + if err != nil { + return 0, err + } + } + s = s[n:] + + // If we have nothing left, we're done. + if len(s) == 0 { + return complex(re, 0), pending + } + + // Otherwise, look at the next character. + switch s[0] { + case '+': + // Consume the '+' to avoid an error if we have "+NaNi", but + // do this only if we don't have a "++" (don't hide that error). + if len(s) > 1 && s[1] != '+' { + s = s[1:] + } + case '-': + // ok + case 'i': + // If 'i' is the last character, we only have an imaginary part. + if len(s) == 1 { + return complex(0, re), pending + } + fallthrough + default: + return 0, syntaxError(fnParseComplex, orig) + } + + // Read imaginary part. + im, n, err := parseFloatPrefix(s, size) + if err != nil { + err, pending = convErr(err, orig) + if err != nil { + return 0, err + } + } + s = s[n:] + if s != "i" { + return 0, syntaxError(fnParseComplex, orig) + } + return complex(re, im), pending +} |