11
11
12
12
use crate :: num:: dec2flt:: common:: { ByteSlice , is_8digits} ;
13
13
14
- /// A decimal floating-point number.
15
- #[ derive( Clone ) ]
16
- pub ( super ) struct Decimal {
14
+ /// A decimal floating-point number, represented as a sequence of decimal digits .
15
+ #[ derive( Clone , Debug , PartialEq ) ]
16
+ pub struct DecimalSeq {
17
17
/// The number of significant digits in the decimal.
18
18
pub num_digits : usize ,
19
19
/// The offset of the decimal point in the significant digits.
@@ -24,13 +24,13 @@ pub(super) struct Decimal {
24
24
pub digits : [ u8 ; Self :: MAX_DIGITS ] ,
25
25
}
26
26
27
- impl Default for Decimal {
27
+ impl Default for DecimalSeq {
28
28
fn default ( ) -> Self {
29
29
Self { num_digits : 0 , decimal_point : 0 , truncated : false , digits : [ 0 ; Self :: MAX_DIGITS ] }
30
30
}
31
31
}
32
32
33
- impl Decimal {
33
+ impl DecimalSeq {
34
34
/// The maximum number of digits required to unambiguously round up to a 64-bit float.
35
35
///
36
36
/// For an IEEE 754 binary64 float, this required 767 digits. So we store the max digits + 1.
@@ -55,7 +55,8 @@ impl Decimal {
55
55
///
56
56
/// In Python:
57
57
/// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))`
58
- pub ( super ) const MAX_DIGITS : usize = 768 ;
58
+ pub const MAX_DIGITS : usize = 768 ;
59
+
59
60
/// The max decimal digits that can be exactly represented in a 64-bit integer.
60
61
pub ( super ) const MAX_DIGITS_WITHOUT_OVERFLOW : usize = 19 ;
61
62
pub ( super ) const DECIMAL_POINT_RANGE : i32 = 2047 ;
@@ -73,12 +74,12 @@ impl Decimal {
73
74
74
75
/// Trim trailing zeros from the buffer.
75
76
// FIXME(tgross35): this could be `.rev().position()` if perf is okay
76
- pub ( super ) fn trim ( & mut self ) {
77
- // All of the following calls to `Decimal ::trim` can't panic because:
77
+ pub fn trim ( & mut self ) {
78
+ // All of the following calls to `DecimalSeq ::trim` can't panic because:
78
79
//
79
- // 1. `parse_decimal` sets `num_digits` to a max of `Decimal ::MAX_DIGITS`.
80
+ // 1. `parse_decimal` sets `num_digits` to a max of `DecimalSeq ::MAX_DIGITS`.
80
81
// 2. `right_shift` sets `num_digits` to `write_index`, which is bounded by `num_digits`.
81
- // 3. `left_shift` `num_digits` to a max of `Decimal ::MAX_DIGITS`.
82
+ // 3. `left_shift` `num_digits` to a max of `DecimalSeq ::MAX_DIGITS`.
82
83
//
83
84
// Trim is only called in `right_shift` and `left_shift`.
84
85
debug_assert ! ( self . num_digits <= Self :: MAX_DIGITS ) ;
@@ -93,21 +94,26 @@ impl Decimal {
93
94
} else if self . decimal_point >= Self :: MAX_DIGITS_WITHOUT_OVERFLOW as i32 {
94
95
return 0xFFFF_FFFF_FFFF_FFFF_u64 ;
95
96
}
97
+
96
98
let dp = self . decimal_point as usize ;
97
99
let mut n = 0_u64 ;
100
+
98
101
for i in 0 ..dp {
99
102
n *= 10 ;
100
103
if i < self . num_digits {
101
104
n += self . digits [ i] as u64 ;
102
105
}
103
106
}
107
+
104
108
let mut round_up = false ;
109
+
105
110
if dp < self . num_digits {
106
111
round_up = self . digits [ dp] >= 5 ;
107
112
if self . digits [ dp] == 5 && dp + 1 == self . num_digits {
108
113
round_up = self . truncated || ( ( dp != 0 ) && ( 1 & self . digits [ dp - 1 ] != 0 ) )
109
114
}
110
115
}
116
+
111
117
if round_up {
112
118
n += 1 ;
113
119
}
@@ -123,6 +129,7 @@ impl Decimal {
123
129
let mut read_index = self . num_digits ;
124
130
let mut write_index = self . num_digits + num_new_digits;
125
131
let mut n = 0_u64 ;
132
+
126
133
while read_index != 0 {
127
134
read_index -= 1 ;
128
135
write_index -= 1 ;
@@ -136,6 +143,7 @@ impl Decimal {
136
143
}
137
144
n = quotient;
138
145
}
146
+
139
147
while n > 0 {
140
148
write_index -= 1 ;
141
149
let quotient = n / 10 ;
@@ -147,10 +155,13 @@ impl Decimal {
147
155
}
148
156
n = quotient;
149
157
}
158
+
150
159
self . num_digits += num_new_digits;
160
+
151
161
if self . num_digits > Self :: MAX_DIGITS {
152
162
self . num_digits = Self :: MAX_DIGITS ;
153
163
}
164
+
154
165
self . decimal_point += num_new_digits as i32 ;
155
166
self . trim ( ) ;
156
167
}
@@ -206,8 +217,8 @@ impl Decimal {
206
217
}
207
218
208
219
/// Parse a big integer representation of the float as a decimal.
209
- pub ( super ) fn parse_decimal ( mut s : & [ u8 ] ) -> Decimal {
210
- let mut d = Decimal :: default ( ) ;
220
+ pub fn parse_decimal_seq ( mut s : & [ u8 ] ) -> DecimalSeq {
221
+ let mut d = DecimalSeq :: default ( ) ;
211
222
let start = s;
212
223
213
224
while let Some ( ( & b'0' , s_next) ) = s. split_first ( ) {
@@ -225,7 +236,7 @@ pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal {
225
236
s = s_next;
226
237
}
227
238
}
228
- while s. len ( ) >= 8 && d. num_digits + 8 < Decimal :: MAX_DIGITS {
239
+ while s. len ( ) >= 8 && d. num_digits + 8 < DecimalSeq :: MAX_DIGITS {
229
240
let v = s. read_u64 ( ) ;
230
241
if !is_8digits ( v) {
231
242
break ;
@@ -237,6 +248,7 @@ pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal {
237
248
s = s. parse_digits ( |digit| d. try_add_digit ( digit) ) ;
238
249
d. decimal_point = s. len ( ) as i32 - first. len ( ) as i32 ;
239
250
}
251
+
240
252
if d. num_digits != 0 {
241
253
// Ignore the trailing zeros if there are any
242
254
let mut n_trailing_zeros = 0 ;
@@ -250,11 +262,12 @@ pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal {
250
262
d. decimal_point += n_trailing_zeros as i32 ;
251
263
d. num_digits -= n_trailing_zeros;
252
264
d. decimal_point += d. num_digits as i32 ;
253
- if d. num_digits > Decimal :: MAX_DIGITS {
265
+ if d. num_digits > DecimalSeq :: MAX_DIGITS {
254
266
d. truncated = true ;
255
- d. num_digits = Decimal :: MAX_DIGITS ;
267
+ d. num_digits = DecimalSeq :: MAX_DIGITS ;
256
268
}
257
269
}
270
+
258
271
if let Some ( ( & ch, s_next) ) = s. split_first ( ) {
259
272
if ch == b'e' || ch == b'E' {
260
273
s = s_next;
@@ -276,13 +289,15 @@ pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal {
276
289
d. decimal_point += if neg_exp { -exp_num } else { exp_num } ;
277
290
}
278
291
}
279
- for i in d. num_digits ..Decimal :: MAX_DIGITS_WITHOUT_OVERFLOW {
292
+
293
+ for i in d. num_digits ..DecimalSeq :: MAX_DIGITS_WITHOUT_OVERFLOW {
280
294
d. digits [ i] = 0 ;
281
295
}
296
+
282
297
d
283
298
}
284
299
285
- fn number_of_digits_decimal_left_shift ( d : & Decimal , mut shift : usize ) -> usize {
300
+ fn number_of_digits_decimal_left_shift ( d : & DecimalSeq , mut shift : usize ) -> usize {
286
301
#[ rustfmt:: skip]
287
302
const TABLE : [ u16 ; 65 ] = [
288
303
0x0000 , 0x0800 , 0x0801 , 0x0803 , 0x1006 , 0x1009 , 0x100D , 0x1812 , 0x1817 , 0x181D , 0x2024 ,
@@ -347,6 +362,7 @@ fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
347
362
let pow5_a = ( 0x7FF & x_a) as usize ;
348
363
let pow5_b = ( 0x7FF & x_b) as usize ;
349
364
let pow5 = & TABLE_POW5 [ pow5_a..] ;
365
+
350
366
for ( i, & p5) in pow5. iter ( ) . enumerate ( ) . take ( pow5_b - pow5_a) {
351
367
if i >= d. num_digits {
352
368
return num_new_digits - 1 ;
@@ -358,5 +374,6 @@ fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
358
374
return num_new_digits;
359
375
}
360
376
}
377
+
361
378
num_new_digits
362
379
}
0 commit comments