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