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 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 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.
@@ -61,7 +61,8 @@ impl Decimal {
61
61
pub const DECIMAL_POINT_RANGE : i32 = 2047 ;
62
62
63
63
/// Append a digit to the buffer if it fits.
64
- // TODO: looks like this
64
+ // todo: should this return `Option`? And should it be incrementing the digit count after
65
+ // it overflows?
65
66
pub fn try_add_digit ( & mut self , digit : u8 ) {
66
67
if self . num_digits < Self :: MAX_DIGITS {
67
68
self . digits [ self . num_digits ] = digit;
@@ -70,13 +71,13 @@ impl Decimal {
70
71
}
71
72
72
73
/// Trim trailing zeros from the buffer.
73
- // TODO : switch to `.rev().position()`
74
+ // todo : switch to `.rev().position()` After tests pass
74
75
pub fn trim ( & mut self ) {
75
- // All of the following calls to `Decimal ::trim` can't panic because:
76
+ // All of the following calls to `DecimalSeq ::trim` can't panic because:
76
77
//
77
- // 1. `parse_decimal` sets `num_digits` to a max of `Decimal ::MAX_DIGITS`.
78
+ // 1. `parse_decimal` sets `num_digits` to a max of `DecimalSeq ::MAX_DIGITS`.
78
79
// 2. `right_shift` sets `num_digits` to `write_index`, which is bounded by `num_digits`.
79
- // 3. `left_shift` `num_digits` to a max of `Decimal ::MAX_DIGITS`.
80
+ // 3. `left_shift` `num_digits` to a max of `DecimalSeq ::MAX_DIGITS`.
80
81
//
81
82
// Trim is only called in `right_shift` and `left_shift`.
82
83
debug_assert ! ( self . num_digits <= Self :: MAX_DIGITS ) ;
@@ -91,21 +92,26 @@ impl Decimal {
91
92
} else if self . decimal_point >= Self :: MAX_DIGITS_WITHOUT_OVERFLOW as i32 {
92
93
return 0xFFFF_FFFF_FFFF_FFFF_u64 ;
93
94
}
95
+
94
96
let dp = self . decimal_point as usize ;
95
97
let mut n = 0_u64 ;
98
+
96
99
for i in 0 ..dp {
97
100
n *= 10 ;
98
101
if i < self . num_digits {
99
102
n += self . digits [ i] as u64 ;
100
103
}
101
104
}
105
+
102
106
let mut round_up = false ;
107
+
103
108
if dp < self . num_digits {
104
109
round_up = self . digits [ dp] >= 5 ;
105
110
if self . digits [ dp] == 5 && dp + 1 == self . num_digits {
106
111
round_up = self . truncated || ( ( dp != 0 ) && ( 1 & self . digits [ dp - 1 ] != 0 ) )
107
112
}
108
113
}
114
+
109
115
if round_up {
110
116
n += 1 ;
111
117
}
@@ -121,6 +127,7 @@ impl Decimal {
121
127
let mut read_index = self . num_digits ;
122
128
let mut write_index = self . num_digits + num_new_digits;
123
129
let mut n = 0_u64 ;
130
+
124
131
while read_index != 0 {
125
132
read_index -= 1 ;
126
133
write_index -= 1 ;
@@ -134,6 +141,7 @@ impl Decimal {
134
141
}
135
142
n = quotient;
136
143
}
144
+
137
145
while n > 0 {
138
146
write_index -= 1 ;
139
147
let quotient = n / 10 ;
@@ -145,10 +153,13 @@ impl Decimal {
145
153
}
146
154
n = quotient;
147
155
}
156
+
148
157
self . num_digits += num_new_digits;
158
+
149
159
if self . num_digits > Self :: MAX_DIGITS {
150
160
self . num_digits = Self :: MAX_DIGITS ;
151
161
}
162
+
152
163
self . decimal_point += num_new_digits as i32 ;
153
164
self . trim ( ) ;
154
165
}
@@ -204,8 +215,8 @@ impl Decimal {
204
215
}
205
216
206
217
/// Parse a big integer representation of the float as a decimal.
207
- pub fn parse_decimal ( mut s : & [ u8 ] ) -> Decimal {
208
- let mut d = Decimal :: default ( ) ;
218
+ pub fn parse_decimal_seq ( mut s : & [ u8 ] ) -> DecimalSeq {
219
+ let mut d = DecimalSeq :: default ( ) ;
209
220
let start = s;
210
221
211
222
while let Some ( ( & b'0' , s_next) ) = s. split_first ( ) {
@@ -223,7 +234,7 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal {
223
234
s = s_next;
224
235
}
225
236
}
226
- while s. len ( ) >= 8 && d. num_digits + 8 < Decimal :: MAX_DIGITS {
237
+ while s. len ( ) >= 8 && d. num_digits + 8 < DecimalSeq :: MAX_DIGITS {
227
238
let v = s. read_u64 ( ) ;
228
239
if !is_8digits ( v) {
229
240
break ;
@@ -235,6 +246,7 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal {
235
246
s = s. parse_digits ( |digit| d. try_add_digit ( digit) ) ;
236
247
d. decimal_point = s. len ( ) as i32 - first. len ( ) as i32 ;
237
248
}
249
+
238
250
if d. num_digits != 0 {
239
251
// Ignore the trailing zeros if there are any
240
252
let mut n_trailing_zeros = 0 ;
@@ -248,11 +260,12 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal {
248
260
d. decimal_point += n_trailing_zeros as i32 ;
249
261
d. num_digits -= n_trailing_zeros;
250
262
d. decimal_point += d. num_digits as i32 ;
251
- if d. num_digits > Decimal :: MAX_DIGITS {
263
+ if d. num_digits > DecimalSeq :: MAX_DIGITS {
252
264
d. truncated = true ;
253
- d. num_digits = Decimal :: MAX_DIGITS ;
265
+ d. num_digits = DecimalSeq :: MAX_DIGITS ;
254
266
}
255
267
}
268
+
256
269
if let Some ( ( & ch, s_next) ) = s. split_first ( ) {
257
270
if ch == b'e' || ch == b'E' {
258
271
s = s_next;
@@ -274,13 +287,15 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal {
274
287
d. decimal_point += if neg_exp { -exp_num } else { exp_num } ;
275
288
}
276
289
}
277
- for i in d. num_digits ..Decimal :: MAX_DIGITS_WITHOUT_OVERFLOW {
290
+
291
+ for i in d. num_digits ..DecimalSeq :: MAX_DIGITS_WITHOUT_OVERFLOW {
278
292
d. digits [ i] = 0 ;
279
293
}
294
+
280
295
d
281
296
}
282
297
283
- fn number_of_digits_decimal_left_shift ( d : & Decimal , mut shift : usize ) -> usize {
298
+ fn number_of_digits_decimal_left_shift ( d : & DecimalSeq , mut shift : usize ) -> usize {
284
299
#[ rustfmt:: skip]
285
300
const TABLE : [ u16 ; 65 ] = [
286
301
0x0000 , 0x0800 , 0x0801 , 0x0803 , 0x1006 , 0x1009 , 0x100D , 0x1812 , 0x1817 , 0x181D , 0x2024 ,
@@ -345,6 +360,7 @@ fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
345
360
let pow5_a = ( 0x7FF & x_a) as usize ;
346
361
let pow5_b = ( 0x7FF & x_b) as usize ;
347
362
let pow5 = & TABLE_POW5 [ pow5_a..] ;
363
+
348
364
for ( i, & p5) in pow5. iter ( ) . enumerate ( ) . take ( pow5_b - pow5_a) {
349
365
if i >= d. num_digits {
350
366
return num_new_digits - 1 ;
@@ -356,5 +372,6 @@ fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
356
372
return num_new_digits;
357
373
}
358
374
}
375
+
359
376
num_new_digits
360
377
}
0 commit comments