]> Cypherpunks.ru repositories - gostls13.git/blob - src/math/big/ratconv.go
all: remove some manual hyphenation
[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 floating-point number
42 // 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         var ecorr int
82         z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
83         if err != nil {
84                 return nil, false
85         }
86
87         // exponent
88         var exp int64
89         exp, _, err = scanExponent(r, false)
90         if err != nil {
91                 return nil, false
92         }
93
94         // there should be no unread characters left
95         if _, err = r.ReadByte(); err != io.EOF {
96                 return nil, false
97         }
98
99         // special-case 0 (see also issue #16176)
100         if len(z.a.abs) == 0 {
101                 return z, true
102         }
103         // len(z.a.abs) > 0
104
105         // correct exponent
106         if ecorr < 0 {
107                 exp += int64(ecorr)
108         }
109
110         // compute exponent power
111         expabs := exp
112         if expabs < 0 {
113                 expabs = -expabs
114         }
115         powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
116
117         // complete fraction
118         if exp < 0 {
119                 z.b.abs = powTen
120                 z.norm()
121         } else {
122                 z.a.abs = z.a.abs.mul(z.a.abs, powTen)
123                 z.b.abs = z.b.abs[:0]
124         }
125
126         z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
127
128         return z, true
129 }
130
131 // scanExponent scans the longest possible prefix of r representing a decimal
132 // ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
133 // exponent base (10 or 2), or a read or syntax error, if any.
134 //
135 //      exponent = ( "E" | "e" | "p" ) [ sign ] digits .
136 //      sign     = "+" | "-" .
137 //      digits   = digit { digit } .
138 //      digit    = "0" ... "9" .
139 //
140 // A binary exponent is only permitted if binExpOk is set.
141 func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
142         base = 10
143
144         var ch byte
145         if ch, err = r.ReadByte(); err != nil {
146                 if err == io.EOF {
147                         err = nil // no exponent; same as e0
148                 }
149                 return
150         }
151
152         switch ch {
153         case 'e', 'E':
154                 // ok
155         case 'p':
156                 if binExpOk {
157                         base = 2
158                         break // ok
159                 }
160                 fallthrough // binary exponent not permitted
161         default:
162                 r.UnreadByte()
163                 return // no exponent; same as e0
164         }
165
166         var neg bool
167         if neg, err = scanSign(r); err != nil {
168                 return
169         }
170
171         var digits []byte
172         if neg {
173                 digits = append(digits, '-')
174         }
175
176         // no need to use nat.scan for exponent digits
177         // since we only care about int64 values - the
178         // from-scratch scan is easy enough and faster
179         for i := 0; ; i++ {
180                 if ch, err = r.ReadByte(); err != nil {
181                         if err != io.EOF || i == 0 {
182                                 return
183                         }
184                         err = nil
185                         break // i > 0
186                 }
187                 if ch < '0' || '9' < ch {
188                         if i == 0 {
189                                 r.UnreadByte()
190                                 err = fmt.Errorf("invalid exponent (missing digits)")
191                                 return
192                         }
193                         break // i > 0
194                 }
195                 digits = append(digits, ch)
196         }
197         // i > 0 => we have at least one digit
198
199         exp, err = strconv.ParseInt(string(digits), 10, 64)
200         return
201 }
202
203 // String returns a string representation of x in the form "a/b" (even if b == 1).
204 func (x *Rat) String() string {
205         var buf []byte
206         buf = x.a.Append(buf, 10)
207         buf = append(buf, '/')
208         if len(x.b.abs) != 0 {
209                 buf = x.b.Append(buf, 10)
210         } else {
211                 buf = append(buf, '1')
212         }
213         return string(buf)
214 }
215
216 // RatString returns a string representation of x in the form "a/b" if b != 1,
217 // and in the form "a" if b == 1.
218 func (x *Rat) RatString() string {
219         if x.IsInt() {
220                 return x.a.String()
221         }
222         return x.String()
223 }
224
225 // FloatString returns a string representation of x in decimal form with prec
226 // digits of precision after the decimal point. The last digit is rounded to
227 // nearest, with halves rounded away from zero.
228 func (x *Rat) FloatString(prec int) string {
229         var buf []byte
230
231         if x.IsInt() {
232                 buf = x.a.Append(buf, 10)
233                 if prec > 0 {
234                         buf = append(buf, '.')
235                         for i := prec; i > 0; i-- {
236                                 buf = append(buf, '0')
237                         }
238                 }
239                 return string(buf)
240         }
241         // x.b.abs != 0
242
243         q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
244
245         p := natOne
246         if prec > 0 {
247                 p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
248         }
249
250         r = r.mul(r, p)
251         r, r2 := r.div(nat(nil), r, x.b.abs)
252
253         // see if we need to round up
254         r2 = r2.add(r2, r2)
255         if x.b.abs.cmp(r2) <= 0 {
256                 r = r.add(r, natOne)
257                 if r.cmp(p) >= 0 {
258                         q = nat(nil).add(q, natOne)
259                         r = nat(nil).sub(r, p)
260                 }
261         }
262
263         if x.a.neg {
264                 buf = append(buf, '-')
265         }
266         buf = append(buf, q.utoa(10)...) // itoa ignores sign if q == 0
267
268         if prec > 0 {
269                 buf = append(buf, '.')
270                 rs := r.utoa(10)
271                 for i := prec - len(rs); i > 0; i-- {
272                         buf = append(buf, '0')
273                 }
274                 buf = append(buf, rs...)
275         }
276
277         return string(buf)
278 }