]> Cypherpunks.ru repositories - gostls13.git/blob - src/math/big/ratconv.go
math/big: permit upper-case 'P' binary exponent (not just 'p')
[gostls13.git] / src / math / big / ratconv.go
1 // Copyright 2015 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 // This file implements rat-to-string conversion functions.
6
7 package big
8
9 import (
10         "errors"
11         "fmt"
12         "io"
13         "strconv"
14         "strings"
15 )
16
17 func ratTok(ch rune) bool {
18         return strings.ContainsRune("+-/0123456789.eE", ch)
19 }
20
21 var ratZero Rat
22 var _ fmt.Scanner = &ratZero // *Rat must implement fmt.Scanner
23
24 // Scan is a support routine for fmt.Scanner. It accepts the formats
25 // 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
26 func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
27         tok, err := s.Token(true, ratTok)
28         if err != nil {
29                 return err
30         }
31         if !strings.ContainsRune("efgEFGv", ch) {
32                 return errors.New("Rat.Scan: invalid verb")
33         }
34         if _, ok := z.SetString(string(tok)); !ok {
35                 return errors.New("Rat.Scan: invalid syntax")
36         }
37         return nil
38 }
39
40 // SetString sets z to the value of s and returns z and a boolean indicating
41 // success. s can be given as a fraction "a/b" or as a decimal floating-point
42 // number optionally followed by an exponent. The entire string (not just a prefix)
43 // must be valid for success. If the operation failed, the value of z is
44 // undefined but the returned value is nil.
45 func (z *Rat) SetString(s string) (*Rat, bool) {
46         if len(s) == 0 {
47                 return nil, false
48         }
49         // len(s) > 0
50
51         // parse fraction a/b, if any
52         if sep := strings.Index(s, "/"); sep >= 0 {
53                 if _, ok := z.a.SetString(s[:sep], 0); !ok {
54                         return nil, false
55                 }
56                 r := strings.NewReader(s[sep+1:])
57                 var err error
58                 if z.b.abs, _, _, err = z.b.abs.scan(r, 0, false); err != nil {
59                         return nil, false
60                 }
61                 // entire string must have been consumed
62                 if _, err = r.ReadByte(); err != io.EOF {
63                         return nil, false
64                 }
65                 if len(z.b.abs) == 0 {
66                         return nil, false
67                 }
68                 return z.norm(), true
69         }
70
71         // parse floating-point number
72         r := strings.NewReader(s)
73
74         // sign
75         neg, err := scanSign(r)
76         if err != nil {
77                 return nil, false
78         }
79
80         // mantissa
81         // TODO(gri) allow other bases besides 10 for mantissa and exponent? (issue #29799)
82         var ecorr int
83         z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
84         if err != nil {
85                 return nil, false
86         }
87
88         // exponent
89         var exp int64
90         exp, _, err = scanExponent(r, false)
91         if err != nil {
92                 return nil, false
93         }
94
95         // there should be no unread characters left
96         if _, err = r.ReadByte(); err != io.EOF {
97                 return nil, false
98         }
99
100         // special-case 0 (see also issue #16176)
101         if len(z.a.abs) == 0 {
102                 return z, true
103         }
104         // len(z.a.abs) > 0
105
106         // correct exponent
107         if ecorr < 0 {
108                 exp += int64(ecorr)
109         }
110
111         // compute exponent power
112         expabs := exp
113         if expabs < 0 {
114                 expabs = -expabs
115         }
116         powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
117
118         // complete fraction
119         if exp < 0 {
120                 z.b.abs = powTen
121                 z.norm()
122         } else {
123                 z.a.abs = z.a.abs.mul(z.a.abs, powTen)
124                 z.b.abs = z.b.abs[:0]
125         }
126
127         z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
128
129         return z, true
130 }
131
132 // scanExponent scans the longest possible prefix of r representing a decimal
133 // ('e', 'E') or binary ('p', 'P') exponent, if any. It returns the exponent,
134 // the exponent base (10 or 2), or a read or syntax error, if any.
135 //
136 //      exponent = ( "e" | "E" | "p" | "P" ) [ sign ] digits .
137 //      sign     = "+" | "-" .
138 //      digits   = digit { digit } .
139 //      digit    = "0" ... "9" .
140 //
141 // A binary exponent is only permitted if binExpOk is set.
142 func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
143         base = 10
144
145         var ch byte
146         if ch, err = r.ReadByte(); err != nil {
147                 if err == io.EOF {
148                         err = nil // no exponent; same as e0
149                 }
150                 return
151         }
152
153         switch ch {
154         case 'e', 'E':
155                 // ok
156         case 'p', 'P':
157                 if binExpOk {
158                         base = 2
159                         break // ok
160                 }
161                 fallthrough // binary exponent not permitted
162         default:
163                 r.UnreadByte()
164                 return // no exponent; same as e0
165         }
166
167         var neg bool
168         if neg, err = scanSign(r); err != nil {
169                 return
170         }
171
172         var digits []byte
173         if neg {
174                 digits = append(digits, '-')
175         }
176
177         // no need to use nat.scan for exponent digits
178         // since we only care about int64 values - the
179         // from-scratch scan is easy enough and faster
180         for i := 0; ; i++ {
181                 if ch, err = r.ReadByte(); err != nil {
182                         if err != io.EOF || i == 0 {
183                                 return
184                         }
185                         err = nil
186                         break // i > 0
187                 }
188                 if ch < '0' || '9' < ch {
189                         if i == 0 {
190                                 r.UnreadByte()
191                                 err = fmt.Errorf("invalid exponent (missing digits)")
192                                 return
193                         }
194                         break // i > 0
195                 }
196                 digits = append(digits, ch)
197         }
198         // i > 0 => we have at least one digit
199
200         exp, err = strconv.ParseInt(string(digits), 10, 64)
201         return
202 }
203
204 // String returns a string representation of x in the form "a/b" (even if b == 1).
205 func (x *Rat) String() string {
206         return string(x.marshal())
207 }
208
209 // marshal implements String returning a slice of bytes
210 func (x *Rat) marshal() []byte {
211         var buf []byte
212         buf = x.a.Append(buf, 10)
213         buf = append(buf, '/')
214         if len(x.b.abs) != 0 {
215                 buf = x.b.Append(buf, 10)
216         } else {
217                 buf = append(buf, '1')
218         }
219         return buf
220 }
221
222 // RatString returns a string representation of x in the form "a/b" if b != 1,
223 // and in the form "a" if b == 1.
224 func (x *Rat) RatString() string {
225         if x.IsInt() {
226                 return x.a.String()
227         }
228         return x.String()
229 }
230
231 // FloatString returns a string representation of x in decimal form with prec
232 // digits of precision after the decimal point. The last digit is rounded to
233 // nearest, with halves rounded away from zero.
234 func (x *Rat) FloatString(prec int) string {
235         var buf []byte
236
237         if x.IsInt() {
238                 buf = x.a.Append(buf, 10)
239                 if prec > 0 {
240                         buf = append(buf, '.')
241                         for i := prec; i > 0; i-- {
242                                 buf = append(buf, '0')
243                         }
244                 }
245                 return string(buf)
246         }
247         // x.b.abs != 0
248
249         q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
250
251         p := natOne
252         if prec > 0 {
253                 p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
254         }
255
256         r = r.mul(r, p)
257         r, r2 := r.div(nat(nil), r, x.b.abs)
258
259         // see if we need to round up
260         r2 = r2.add(r2, r2)
261         if x.b.abs.cmp(r2) <= 0 {
262                 r = r.add(r, natOne)
263                 if r.cmp(p) >= 0 {
264                         q = nat(nil).add(q, natOne)
265                         r = nat(nil).sub(r, p)
266                 }
267         }
268
269         if x.a.neg {
270                 buf = append(buf, '-')
271         }
272         buf = append(buf, q.utoa(10)...) // itoa ignores sign if q == 0
273
274         if prec > 0 {
275                 buf = append(buf, '.')
276                 rs := r.utoa(10)
277                 for i := prec - len(rs); i > 0; i-- {
278                         buf = append(buf, '0')
279                 }
280                 buf = append(buf, rs...)
281         }
282
283         return string(buf)
284 }