Skip to content

Commit 8afa9a5

Browse files
committed
- added ParseComplex function
1 parent 55b2570 commit 8afa9a5

File tree

3 files changed

+172
-4
lines changed

3 files changed

+172
-4
lines changed

src/strconv/atoc.go

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Copyright 2009 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package strconv
6+
7+
func convErr(err error, s string) error {
8+
if x, ok := err.(*NumError); ok {
9+
x.Func = fnParseComplex
10+
x.Num = s
11+
}
12+
return err
13+
}
14+
15+
func parseFloat(s, orig string, bitSize int) (float64, error) {
16+
if bitSize == 64 {
17+
f, err := ParseFloat(s, 32)
18+
if err != nil {
19+
return 0, convErr(err, orig)
20+
}
21+
return f, nil
22+
}
23+
24+
f, err := ParseFloat(s, 64)
25+
if err != nil {
26+
return 0, convErr(err, orig)
27+
}
28+
return f, nil
29+
}
30+
31+
const fnParseComplex = "ParseComplex"
32+
33+
// ParseComplex converts the string s to a complex number
34+
// with the precision specified by bitSize: 64 for complex64, or 128 for complex128.
35+
// When bitSize=64, the result still has type complex128, but it will be
36+
// convertible to complex64 without changing its value.
37+
//
38+
// The number represented by s may or may not be parenthesized and have the format (N+Ni) where N is
39+
// a floating-point number. There must not be spaces between the real and imaginary components.
40+
//
41+
// ParseComplex accepts decimal and hexadecimal floating-point number syntax.
42+
// If s is well-formed and near a valid floating-point number,
43+
// ParseComplex returns the nearest floating-point number rounded
44+
// using IEEE754 unbiased rounding.
45+
// (Parsing a hexadecimal floating-point value only rounds when
46+
// there are more bits in the hexadecimal representation than
47+
// will fit in the mantissa.)
48+
//
49+
// The errors that ParseComplex returns have concrete type *NumError
50+
// and include err.Num = s.
51+
//
52+
// If s is not syntactically well-formed, ParseComplex returns err.Err = ErrSyntax.
53+
//
54+
// If s is syntactically well-formed but is more than 1/2 ULP
55+
// away from the largest floating point number of the given size,
56+
// ParseComplex returns f = ±Inf, err.Err = ErrRange.
57+
//
58+
// ParseComplex recognizes the strings "NaN", "+Inf", and "-Inf" as their
59+
// respective special floating point values for each component. It ignores case when matching.
60+
func ParseComplex(s string, bitSize int) (complex128, error) {
61+
62+
orig := s
63+
64+
if len(s) == 0 {
65+
return 0, syntaxError(fnParseComplex, orig)
66+
}
67+
68+
lastChar := s[len(s)-1 : len(s)]
69+
70+
// Remove brackets
71+
if len(s) > 1 && s[0:1] == "(" && lastChar == ")" {
72+
s = s[1 : len(s)-1]
73+
lastChar = s[len(s)-1 : len(s)]
74+
}
75+
76+
// Is last character an i?
77+
if lastChar != "i" {
78+
// The last character is not an i so there is only a real component.
79+
real, err := parseFloat(s, orig, bitSize)
80+
if err != nil {
81+
return 0, err
82+
}
83+
return complex(real, 0), nil
84+
}
85+
86+
// Remove last char which is an i
87+
s = s[0 : len(s)-1]
88+
89+
// Count how many ± exist.
90+
pos := []int{}
91+
92+
for idx, rune := range s {
93+
if rune == '+' || rune == '-' {
94+
pos = append(pos, idx)
95+
}
96+
}
97+
98+
if len(pos) == 0 {
99+
// There is only an imaginary component
100+
101+
if s == "" {
102+
s = "1"
103+
}
104+
105+
imag, err := parseFloat(s, orig, bitSize)
106+
if err != nil {
107+
return 0, err
108+
}
109+
return complex(0, imag), nil
110+
111+
} else if len(pos) > 4 {
112+
// Too many ± exists for a valid complex number
113+
return 0, syntaxError(fnParseComplex, orig)
114+
}
115+
116+
/* From here onwards, it is either complex number with both a real and imaginary component OR a pure imaginary number in exponential form. */
117+
118+
// Loop through pos from middle of slice, outwards
119+
mid := (len(pos) - 1) >> 1
120+
for j := 0; j < len(pos); j++ {
121+
var idx int
122+
if j%2 == 0 {
123+
idx = mid - j/2
124+
} else {
125+
idx = mid + (j/2 + 1)
126+
}
127+
128+
left := s[0:pos[idx]]
129+
right := s[pos[idx]:]
130+
131+
// Check if left and right are valid float64
132+
real, err := parseFloat(left, orig, bitSize)
133+
if err != nil {
134+
continue
135+
}
136+
137+
if right == "+" || right == "-" {
138+
right = right + "1"
139+
}
140+
141+
imag, err := parseFloat(right, orig, bitSize)
142+
if err != nil {
143+
continue
144+
}
145+
146+
return complex(real, imag), nil
147+
}
148+
149+
// Pure imaginary number in exponential form
150+
imag, err := parseFloat(s, orig, bitSize)
151+
if err != nil {
152+
return 0, err
153+
}
154+
return complex(0, imag), nil
155+
}

src/strconv/atoc_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2009 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package strconv_test
6+
7+
import ()
8+
9+
// Test cases required:
10+
// hex form
11+
// exp form
12+
// Only real
13+
// Only imag
14+
// Both real and imag
15+
// With and without parentheses
16+
// NaN
17+
// ±Inf

src/strconv/atof.go

-4
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,3 @@ func ParseFloat(s string, bitSize int) (float64, error) {
678678
}
679679
return atof64(s)
680680
}
681-
682-
func ParseComplex(s string, bitSize int) (float64, error) {
683-
return 0,nil
684-
}

0 commit comments

Comments
 (0)