@@ -38,10 +38,22 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
38
38
}
39
39
40
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.
41
+ // success. s can be given as a (possibly signed) fraction "a/b", or as a
42
+ // floating-point number optionally followed by an exponent.
43
+ // If a fraction is provided, both the dividend and the divisor may be a
44
+ // decimal integer or independently use a prefix of ``0b'', ``0'' or ``0o'',
45
+ // or ``0x'' (or their upper-case variants) to denote a binary, octal, or
46
+ // hexadecimal integer, respectively. The divisor may not be signed.
47
+ // If a floating-point number is provided, it may be in decimal form or
48
+ // use any of the same prefixes as above but for ``0'' to denote a non-decimal
49
+ // mantissa. A leading ``0'' is considered a decimal leading 0; it does not
50
+ // indicate octal representation in this case.
51
+ // An optional base-10 ``e'' or base-2 ``p'' (or their upper-case variants)
52
+ // exponent may be provided as well, except for hexadecimal floats which
53
+ // only accept an (optional) ``p'' exponent (because an ``e'' or ``E'' cannot
54
+ // be distinguished from a mantissa digit).
55
+ // The entire string, not just a prefix, must be valid for success. If the
56
+ // operation failed, the value of z is undefined but the returned value is nil.
45
57
func (z * Rat ) SetString (s string ) (* Rat , bool ) {
46
58
if len (s ) == 0 {
47
59
return nil , false
@@ -78,16 +90,17 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
78
90
}
79
91
80
92
// 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 )
93
+ var base int
94
+ var fcount int // fractional digit count; valid if <= 0
95
+ z .a .abs , base , fcount , err = z .a .abs .scan (r , 0 , true )
84
96
if err != nil {
85
97
return nil , false
86
98
}
87
99
88
100
// exponent
89
101
var exp int64
90
- exp , _ , err = scanExponent (r , false , false )
102
+ var ebase int
103
+ exp , ebase , err = scanExponent (r , true , true )
91
104
if err != nil {
92
105
return nil , false
93
106
}
@@ -103,30 +116,91 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
103
116
}
104
117
// len(z.a.abs) > 0
105
118
106
- // correct exponent
107
- if ecorr < 0 {
108
- exp += int64 (ecorr )
119
+ // The mantissa may have a radix point (fcount <= 0) and there
120
+ // may be a nonzero exponent exp. The radix point amounts to a
121
+ // division by base**(-fcount), which equals a multiplication by
122
+ // base**fcount. An exponent means multiplication by ebase**exp.
123
+ // Multiplications are commutative, so we can apply them in any
124
+ // order. We only have powers of 2 and 10, and we split powers
125
+ // of 10 into the product of the same powers of 2 and 5. This
126
+ // may reduce the the size of shift/multiplication factors or
127
+ // divisors required to create the final fraction, depending
128
+ // on the actual floating-point value.
129
+
130
+ // determine binary or decimal exponent contribution of radix point
131
+ var exp2 , exp5 int64
132
+ if fcount < 0 {
133
+ // The mantissa has a radix point ddd.dddd; and
134
+ // -fcount is the number of digits to the right
135
+ // of '.'. Adjust relevant exponent accordingly.
136
+ d := int64 (fcount )
137
+ switch base {
138
+ case 10 :
139
+ exp5 = d
140
+ fallthrough // 10**e == 5**e * 2**e
141
+ case 2 :
142
+ exp2 = d
143
+ case 8 :
144
+ exp2 = d * 3 // octal digits are 3 bits each
145
+ case 16 :
146
+ exp2 = d * 4 // hexadecimal digits are 4 bits each
147
+ default :
148
+ panic ("unexpected mantissa base" )
149
+ }
150
+ // fcount consumed - not needed anymore
109
151
}
110
152
111
- // compute exponent power
112
- expabs := exp
113
- if expabs < 0 {
114
- expabs = - expabs
153
+ // take actual exponent into account
154
+ switch ebase {
155
+ case 10 :
156
+ exp5 += exp
157
+ fallthrough // see fallthrough above
158
+ case 2 :
159
+ exp2 += exp
160
+ default :
161
+ panic ("unexpected exponent base" )
162
+ }
163
+ // exp consumed - not needed anymore
164
+
165
+ // compute pow5 if needed
166
+ pow5 := z .b .abs
167
+ if exp5 != 0 {
168
+ n := exp5
169
+ if n < 0 {
170
+ n = - n
171
+ }
172
+ pow5 = pow5 .expNN (natFive , nat (nil ).setWord (Word (n )), nil )
115
173
}
116
- powTen := nat (nil ).expNN (natTen , nat (nil ).setWord (Word (expabs )), nil )
117
174
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 ]
175
+ // apply dividend contributions of exponents
176
+ // (start with exp5 so the numbers to multiply are smaller)
177
+ if exp5 > 0 {
178
+ z .a .abs = z .a .abs .mul (z .a .abs , pow5 )
179
+ exp5 = 0
180
+ }
181
+ if exp2 > 0 {
182
+ if int64 (uint (exp2 )) != exp2 {
183
+ panic ("exponent too large" )
184
+ }
185
+ z .a .abs = z .a .abs .shl (z .a .abs , uint (exp2 ))
186
+ exp2 = 0
187
+ }
188
+
189
+ // apply divisor contributions of exponents
190
+ z .b .abs = z .b .abs .setWord (1 )
191
+ if exp5 < 0 {
192
+ z .b .abs = pow5
193
+ }
194
+ if exp2 < 0 {
195
+ if int64 (uint (- exp2 )) != - exp2 {
196
+ panic ("exponent too large" )
197
+ }
198
+ z .b .abs = z .b .abs .shl (z .b .abs , uint (- exp2 ))
125
199
}
126
200
127
201
z .a .neg = neg && len (z .a .abs ) > 0 // 0 has no sign
128
202
129
- return z , true
203
+ return z . norm () , true
130
204
}
131
205
132
206
// scanExponent scans the longest possible prefix of r representing a base 10
@@ -250,7 +324,7 @@ func (x *Rat) RatString() string {
250
324
}
251
325
252
326
// FloatString returns a string representation of x in decimal form with prec
253
- // digits of precision after the decimal point. The last digit is rounded to
327
+ // digits of precision after the radix point. The last digit is rounded to
254
328
// nearest, with halves rounded away from zero.
255
329
func (x * Rat ) FloatString (prec int ) string {
256
330
var buf []byte
0 commit comments