]> Cypherpunks.ru repositories - gostls13.git/blob - src/math/big/ratconv.go
[dev.cc] all: merge master (b8fcae0) into dev.cc
[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.IndexRune("+-/0123456789.eE", ch) >= 0
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.IndexRune("efgEFGv", ch) < 0 {
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         var ebase int
82         exp, ebase, err = scanExponent(r)
83         if ebase == 2 || err != nil {
84                 return nil, false
85         }
86
87         // there should be no unread characters left
88         if _, err = r.ReadByte(); err != io.EOF {
89                 return nil, false
90         }
91
92         // correct exponent
93         if ecorr < 0 {
94                 exp += int64(ecorr)
95         }
96
97         // compute exponent power
98         expabs := exp
99         if expabs < 0 {
100                 expabs = -expabs
101         }
102         powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
103
104         // complete fraction
105         if exp < 0 {
106                 z.b.abs = powTen
107                 z.norm()
108         } else {
109                 z.a.abs = z.a.abs.mul(z.a.abs, powTen)
110                 z.b.abs = z.b.abs[:0]
111         }
112
113         z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
114
115         return z, true
116 }
117
118 func scanExponent(r io.ByteScanner) (exp int64, base int, err error) {
119         base = 10
120
121         var ch byte
122         if ch, err = r.ReadByte(); err != nil {
123                 if err == io.EOF {
124                         err = nil // no exponent; same as e0
125                 }
126                 return
127         }
128
129         switch ch {
130         case 'e', 'E':
131                 // ok
132         case 'p':
133                 base = 2
134         default:
135                 r.UnreadByte()
136                 return // no exponent; same as e0
137         }
138
139         var neg bool
140         if neg, err = scanSign(r); err != nil {
141                 return
142         }
143
144         var digits []byte
145         if neg {
146                 digits = append(digits, '-')
147         }
148
149         // no need to use nat.scan for exponent digits
150         // since we only care about int64 values - the
151         // from-scratch scan is easy enough and faster
152         for i := 0; ; i++ {
153                 if ch, err = r.ReadByte(); err != nil {
154                         if err != io.EOF || i == 0 {
155                                 return
156                         }
157                         err = nil
158                         break // i > 0
159                 }
160                 if ch < '0' || '9' < ch {
161                         if i == 0 {
162                                 r.UnreadByte()
163                                 err = fmt.Errorf("invalid exponent (missing digits)")
164                                 return
165                         }
166                         break // i > 0
167                 }
168                 digits = append(digits, byte(ch))
169         }
170         // i > 0 => we have at least one digit
171
172         exp, err = strconv.ParseInt(string(digits), 10, 64)
173         return
174 }
175
176 // String returns a string representation of x in the form "a/b" (even if b == 1).
177 func (x *Rat) String() string {
178         s := "/1"
179         if len(x.b.abs) != 0 {
180                 s = "/" + x.b.abs.decimalString()
181         }
182         return x.a.String() + s
183 }
184
185 // RatString returns a string representation of x in the form "a/b" if b != 1,
186 // and in the form "a" if b == 1.
187 func (x *Rat) RatString() string {
188         if x.IsInt() {
189                 return x.a.String()
190         }
191         return x.String()
192 }
193
194 // FloatString returns a string representation of x in decimal form with prec
195 // digits of precision after the decimal point and the last digit rounded.
196 func (x *Rat) FloatString(prec int) string {
197         if x.IsInt() {
198                 s := x.a.String()
199                 if prec > 0 {
200                         s += "." + strings.Repeat("0", prec)
201                 }
202                 return s
203         }
204         // x.b.abs != 0
205
206         q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
207
208         p := natOne
209         if prec > 0 {
210                 p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
211         }
212
213         r = r.mul(r, p)
214         r, r2 := r.div(nat(nil), r, x.b.abs)
215
216         // see if we need to round up
217         r2 = r2.add(r2, r2)
218         if x.b.abs.cmp(r2) <= 0 {
219                 r = r.add(r, natOne)
220                 if r.cmp(p) >= 0 {
221                         q = nat(nil).add(q, natOne)
222                         r = nat(nil).sub(r, p)
223                 }
224         }
225
226         s := q.decimalString()
227         if x.a.neg {
228                 s = "-" + s
229         }
230
231         if prec > 0 {
232                 rs := r.decimalString()
233                 leadingZeros := prec - len(rs)
234                 s += "." + strings.Repeat("0", leadingZeros) + rs
235         }
236
237         return s
238 }