106 lines
3.0 KiB
Go
106 lines
3.0 KiB
Go
// 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 := 128
|
|
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
|
|
}
|