Skip to main content

litex/rational_expression/
evaluate.rs

1use crate::common::count_range_integer::{
2    count_closed_range_integer_endpoints, count_half_open_range_integer_endpoints,
3};
4use crate::prelude::*;
5use crate::rational_expression::evaluate_div::safe_div;
6
7impl Obj {
8    pub fn evaluate_to_normalized_decimal_number(&self) -> Option<Number> {
9        let result = match self {
10            Obj::Number(number) => Some(number.clone()),
11            Obj::Add(add) => {
12                let left_number = add.left.evaluate_to_normalized_decimal_number();
13                let right_number = add.right.evaluate_to_normalized_decimal_number();
14                if let (Some(left_number), Some(right_number)) = (left_number, right_number) {
15                    let a = &left_number.normalized_value;
16                    let b = &right_number.normalized_value;
17                    let sum = if normalized_decimal_str_is_non_negative(a)
18                        && normalized_decimal_str_is_non_negative(b)
19                    {
20                        // `add_decimal_str_and_normalize` 仅适用于两操作数非负(见函数注释)
21                        add_decimal_str_and_normalize(a, b)
22                    } else {
23                        add_signed_decimal_str(a, b)
24                    };
25                    Some(Number::new(sum))
26                } else {
27                    None
28                }
29            }
30            Obj::Sub(sub) => {
31                let left_number = sub.left.evaluate_to_normalized_decimal_number();
32                let right_number = sub.right.evaluate_to_normalized_decimal_number();
33                if let (Some(left_number), Some(right_number)) = (left_number, right_number) {
34                    let a = &left_number.normalized_value;
35                    let b = &right_number.normalized_value;
36                    let diff = if normalized_decimal_str_is_non_negative(a)
37                        && normalized_decimal_str_is_non_negative(b)
38                    {
39                        // `sub_decimal_str_and_normalize` 的竖式比较同样按非负量设计
40                        sub_decimal_str_and_normalize(a, b)
41                    } else {
42                        sub_signed_decimal_str(a, b)
43                    };
44                    Some(Number::new(diff))
45                } else {
46                    None
47                }
48            }
49            Obj::Mul(mul) => {
50                let left_number = mul.left.evaluate_to_normalized_decimal_number();
51                let right_number = mul.right.evaluate_to_normalized_decimal_number();
52                if let (Some(left_number), Some(right_number)) = (left_number, right_number) {
53                    Some(Number::new(mul_signed_decimal_str(
54                        &left_number.normalized_value,
55                        &right_number.normalized_value,
56                    )))
57                } else {
58                    None
59                }
60            }
61            Obj::Mod(mod_obj) => {
62                let left_number = mod_obj.left.evaluate_to_normalized_decimal_number();
63                let right_number = mod_obj.right.evaluate_to_normalized_decimal_number();
64                if let (Some(left_number), Some(right_number)) = (left_number, right_number) {
65                    Some(Number::new(mod_decimal_str_and_normalize(
66                        &left_number.normalized_value,
67                        &right_number.normalized_value,
68                    )))
69                } else {
70                    None
71                }
72            }
73            Obj::Pow(pow_obj) => {
74                let base_number = pow_obj.base.evaluate_to_normalized_decimal_number();
75                let exponent_number = pow_obj.exponent.evaluate_to_normalized_decimal_number();
76                if let (Some(base_number), Some(exponent_number)) = (base_number, exponent_number) {
77                    pow_decimal_str_and_normalize(
78                        &base_number.normalized_value,
79                        &exponent_number.normalized_value,
80                    )
81                    .map(Number::new)
82                } else {
83                    None
84                }
85            }
86            Obj::Div(div) => {
87                let left_number = div.left.evaluate_to_normalized_decimal_number();
88                let right_number = div.right.evaluate_to_normalized_decimal_number();
89                if let (Some(left_number), Some(right_number)) = (left_number, right_number) {
90                    let exact_quotient_string = safe_div(
91                        &left_number.normalized_value,
92                        &right_number.normalized_value,
93                    );
94
95                    if let Some(exact_quotient_string) = exact_quotient_string {
96                        Some(Number::new(exact_quotient_string))
97                    } else {
98                        None
99                    }
100                } else {
101                    return None;
102                }
103            }
104            Obj::Abs(a) => match a.arg.evaluate_to_normalized_decimal_number() {
105                Some(inner) => {
106                    let s = inner.normalized_value.trim();
107                    if let Some(rest) = s.strip_prefix('-') {
108                        Some(Number::new(rest.trim().to_string()))
109                    } else {
110                        Some(inner)
111                    }
112                }
113                None => None,
114            },
115            Obj::Max(m) => {
116                let left_number = m.left.evaluate_to_normalized_decimal_number();
117                let right_number = m.right.evaluate_to_normalized_decimal_number();
118                if let (Some(left_number), Some(right_number)) = (left_number, right_number) {
119                    let a = left_number.normalized_value.trim();
120                    let b = right_number.normalized_value.trim();
121                    let diff = sub_signed_decimal_str(a, b);
122                    let d = diff.trim();
123                    if d.starts_with('-') {
124                        Some(right_number)
125                    } else {
126                        Some(left_number)
127                    }
128                } else {
129                    None
130                }
131            }
132            Obj::Min(m) => {
133                let left_number = m.left.evaluate_to_normalized_decimal_number();
134                let right_number = m.right.evaluate_to_normalized_decimal_number();
135                if let (Some(left_number), Some(right_number)) = (left_number, right_number) {
136                    let a = left_number.normalized_value.trim();
137                    let b = right_number.normalized_value.trim();
138                    let diff = sub_signed_decimal_str(a, b);
139                    let d = diff.trim();
140                    if d.starts_with('-') || d == "0" {
141                        Some(left_number)
142                    } else {
143                        Some(right_number)
144                    }
145                } else {
146                    None
147                }
148            }
149            Obj::CartDim(cart_dim) => match &*cart_dim.set {
150                Obj::Cart(cart) => Some(Number::new(cart.args.len().to_string())),
151                _ => None,
152            },
153            Obj::TupleDim(tuple_dim) => match &*tuple_dim.arg {
154                Obj::Tuple(tuple) => Some(Number::new(tuple.args.len().to_string())),
155                _ => None,
156            },
157            Obj::Count(count) => match &*count.set {
158                Obj::ListSet(list_set) => Some(Number::new(list_set.list.len().to_string())),
159                Obj::ClosedRange(cr) => {
160                    let a = cr.start.evaluate_to_normalized_decimal_number()?;
161                    let b = cr.end.evaluate_to_normalized_decimal_number()?;
162                    count_closed_range_integer_endpoints(&a, &b)
163                }
164                Obj::Range(r) => {
165                    let a = r.start.evaluate_to_normalized_decimal_number()?;
166                    let b = r.end.evaluate_to_normalized_decimal_number()?;
167                    count_half_open_range_integer_endpoints(&a, &b)
168                }
169                _ => None,
170            },
171            _ => None,
172        };
173
174        match result {
175            Some(number) => Some(number),
176            None => None,
177        }
178    }
179
180    pub fn two_objs_can_be_calculated_and_equal_by_calculation(&self, other: &Obj) -> bool {
181        match (
182            self.evaluate_to_normalized_decimal_number(),
183            other.evaluate_to_normalized_decimal_number(),
184        ) {
185            (Some(left_number), Some(right_number)) => {
186                return left_number.normalized_value == right_number.normalized_value;
187            }
188            _ => return false,
189        }
190    }
191}
192
193/// 规范化后的十进制串是否表示非负数(无 `-` 前缀;`-0` 若已规范为 `0` 亦视为非负)。
194fn normalized_decimal_str_is_non_negative(s: &str) -> bool {
195    !s.trim().starts_with('-')
196}
197
198fn split_sign_and_magnitude(number_string: &str) -> (bool, String) {
199    let trimmed_number_string = number_string.trim();
200    if let Some(stripped_number_string) = trimmed_number_string.strip_prefix('-') {
201        (true, stripped_number_string.trim().to_string())
202    } else {
203        (false, trimmed_number_string.to_string())
204    }
205}
206
207pub fn mul_signed_decimal_str(left_number_string: &str, right_number_string: &str) -> String {
208    let (left_is_negative, left_magnitude_number_string) =
209        split_sign_and_magnitude(left_number_string);
210    let (right_is_negative, right_magnitude_number_string) =
211        split_sign_and_magnitude(right_number_string);
212    let multiplied_magnitude_number_string = mul_decimal_str_and_normalize(
213        &left_magnitude_number_string,
214        &right_magnitude_number_string,
215    );
216    let multiplied_magnitude_is_zero = multiplied_magnitude_number_string == "0";
217    let multiplied_result_is_negative = left_is_negative ^ right_is_negative;
218    if multiplied_result_is_negative && !multiplied_magnitude_is_zero {
219        normalize_decimal_number_string(&format!("-{}", multiplied_magnitude_number_string))
220    } else {
221        normalize_decimal_number_string(&multiplied_magnitude_number_string)
222    }
223}
224
225/// 带符号加法 a + b(系数合并用;`add_decimal_str_and_normalize` 仅适用于非负操作数)
226pub fn add_signed_decimal_str(a: &str, b: &str) -> String {
227    let (a_neg, a_mag) = split_sign_and_magnitude(a);
228    let (b_neg, b_mag) = split_sign_and_magnitude(b);
229    match (a_neg, b_neg) {
230        (false, false) => add_decimal_str_and_normalize(&a_mag, &b_mag),
231        (true, true) => {
232            let sum_mag = add_decimal_str_and_normalize(&a_mag, &b_mag);
233            if sum_mag == "0" {
234                "0".to_string()
235            } else {
236                normalize_decimal_number_string(&format!("-{}", sum_mag))
237            }
238        }
239        (false, true) => sub_decimal_str_and_normalize(&a_mag, &b_mag),
240        (true, false) => sub_decimal_str_and_normalize(&b_mag, &a_mag),
241    }
242}
243
244/// 带符号减法 a - b
245pub fn sub_signed_decimal_str(a: &str, b: &str) -> String {
246    add_signed_decimal_str(a, &mul_signed_decimal_str(b, "-1"))
247}
248
249impl Obj {
250    pub fn replace_with_numeric_result_if_can_be_calculated(&self) -> (Obj, bool) {
251        if let Some(calculated_number) = self.evaluate_to_normalized_decimal_number() {
252            (Obj::Number(calculated_number), true)
253        } else {
254            (self.clone(), false)
255        }
256    }
257}
258
259/// 竖式加法:两个表示非负数的数字串(可含小数点),返回和的字符串
260pub fn add_decimal_str_and_normalize(a: &str, b: &str) -> String {
261    let (mut int_a, mut frac_a) = parse_decimal_parts(a);
262    let (mut int_b, mut frac_b) = parse_decimal_parts(b);
263    let frac_len = frac_a.len().max(frac_b.len());
264    frac_a.resize(frac_len, 0);
265    frac_b.resize(frac_len, 0);
266    let int_len = int_a.len().max(int_b.len());
267    int_a.reverse();
268    int_b.reverse();
269    int_a.resize(int_len, 0);
270    int_b.resize(int_len, 0);
271
272    let mut out_frac = vec![0u8; frac_len];
273    let mut carry = 0u8;
274    for i in (0..frac_len).rev() {
275        let sum = frac_a[i] + frac_b[i] + carry;
276        out_frac[i] = sum % 10;
277        carry = sum / 10;
278    }
279    let mut out_int = Vec::with_capacity(int_len + 1);
280    for i in 0..int_len {
281        let sum = int_a[i] + int_b[i] + carry;
282        out_int.push(sum % 10);
283        carry = sum / 10;
284    }
285    if carry > 0 {
286        out_int.push(carry);
287    }
288    out_int.reverse();
289
290    let int_str: String = out_int.iter().map(|&d| (b'0' + d) as char).collect();
291    let frac_str: String = out_frac.iter().map(|&d| (b'0' + d) as char).collect();
292    let result = if frac_str.is_empty() || out_frac.iter().all(|&d| d == 0) {
293        int_str
294    } else {
295        format!("{}.{}", int_str, frac_str.trim_end_matches('0'))
296    };
297    normalize_decimal_number_string(&result)
298}
299
300/// 竖式减法:a - b,若 a >= b 返回非负结果字符串,否则返回 "-" + (b - a) 的字符串
301pub fn sub_decimal_str_and_normalize(a: &str, b: &str) -> String {
302    let (int_a, frac_a) = parse_decimal_parts(a);
303    let (int_b, frac_b) = parse_decimal_parts(b);
304    let frac_len = frac_a.len().max(frac_b.len());
305    let mut fa: Vec<u8> = frac_a.iter().cloned().collect();
306    let mut fb: Vec<u8> = frac_b.iter().cloned().collect();
307    fa.resize(frac_len, 0);
308    fb.resize(frac_len, 0);
309    let int_len = int_a.len().max(int_b.len());
310    let mut ia: Vec<u8> = int_a.iter().cloned().collect();
311    let mut ib: Vec<u8> = int_b.iter().cloned().collect();
312    ia.reverse();
313    ib.reverse();
314    ia.resize(int_len, 0);
315    ib.resize(int_len, 0);
316
317    let cmp = compare_decimal_parts(&ia, &fa, &ib, &fb);
318    let (top_int, top_frac, bot_int, bot_frac) = if cmp >= 0 {
319        (ia, fa, ib, fb)
320    } else {
321        let inner = sub_decimal_str_and_normalize(b, a);
322        return normalize_decimal_number_string(&format!("-{}", inner));
323    };
324
325    let mut out_frac = vec![0u8; frac_len];
326    let mut borrow: i16 = 0;
327    for i in (0..frac_len).rev() {
328        let mut d = top_frac[i] as i16 - bot_frac[i] as i16 - borrow;
329        borrow = 0;
330        if d < 0 {
331            d += 10;
332            borrow = 1;
333        }
334        out_frac[i] = d as u8;
335    }
336    let mut out_int = Vec::with_capacity(int_len);
337    for i in 0..int_len {
338        let mut d = top_int[i] as i16 - bot_int[i] as i16 - borrow;
339        borrow = 0;
340        if d < 0 {
341            d += 10;
342            borrow = 1;
343        }
344        out_int.push(d as u8);
345    }
346    out_int.reverse();
347    let start = out_int
348        .iter()
349        .position(|&d| d != 0)
350        .unwrap_or(out_int.len().saturating_sub(1));
351    let out_int = out_int[start..].to_vec();
352
353    let int_str: String = if out_int.is_empty() {
354        "0".to_string()
355    } else {
356        out_int.iter().map(|&d| (b'0' + d) as char).collect()
357    };
358    let frac_str: String = out_frac.iter().map(|&d| (b'0' + d) as char).collect();
359    let frac_trim = frac_str.trim_end_matches('0');
360    let result = if frac_trim.is_empty() {
361        int_str
362    } else {
363        format!("{}.{}", int_str, frac_trim)
364    };
365    normalize_decimal_number_string(&result)
366}
367
368fn compare_decimal_parts(int_a: &[u8], frac_a: &[u8], int_b: &[u8], frac_b: &[u8]) -> i32 {
369    let len_a = int_a.len();
370    let len_b = int_b.len();
371    if len_a != len_b {
372        return (len_a as i32) - (len_b as i32);
373    }
374    for i in (0..len_a).rev() {
375        if int_a[i] != int_b[i] {
376            return int_a[i] as i32 - int_b[i] as i32;
377        }
378    }
379    for i in 0..frac_a.len().max(frac_b.len()) {
380        let da = match frac_a.get(i) {
381            Some(&d) => d,
382            None => 0,
383        };
384        let db = match frac_b.get(i) {
385            Some(&d) => d,
386            None => 0,
387        };
388        if da != db {
389            return da as i32 - db as i32;
390        }
391    }
392    0
393}
394
395/// 竖式乘法:两个非负数字串,返回积的字符串(product[0]=个位,即最低位)
396pub fn mul_decimal_str_and_normalize(a: &str, b: &str) -> String {
397    let (int_a, frac_a) = parse_decimal_parts(a);
398    let (int_b, frac_b) = parse_decimal_parts(b);
399    let frac_places = frac_a.len() + frac_b.len();
400    let digits_a: Vec<u8> = int_a
401        .iter()
402        .cloned()
403        .chain(frac_a.iter().cloned())
404        .collect();
405    let digits_b: Vec<u8> = int_b
406        .iter()
407        .cloned()
408        .chain(frac_b.iter().cloned())
409        .collect();
410    let len_a = digits_a.len();
411    let len_b = digits_b.len();
412    let mut product = vec![0u32; len_a + len_b];
413    for (i, &da) in digits_a.iter().enumerate() {
414        for (j, &db) in digits_b.iter().enumerate() {
415            let place = (len_a - 1 - i) + (len_b - 1 - j);
416            product[place] += da as u32 * db as u32;
417        }
418    }
419    let mut carry = 0u32;
420    for p in product.iter_mut() {
421        *p += carry;
422        carry = *p / 10;
423        *p %= 10;
424    }
425    while carry > 0 {
426        product.push(carry % 10);
427        carry /= 10;
428    }
429    let total_len = product.len();
430    let int_part: String = if frac_places >= total_len {
431        "0".to_string()
432    } else {
433        product[frac_places..]
434            .iter()
435            .rev()
436            .map(|&d| (b'0' + d as u8) as char)
437            .collect::<String>()
438            .trim_start_matches('0')
439            .to_string()
440    };
441    let frac_part: String = if frac_places == 0 {
442        String::new()
443    } else {
444        product[..frac_places.min(total_len)]
445            .iter()
446            .rev()
447            .map(|&d| (b'0' + d as u8) as char)
448            .collect::<String>()
449            .trim_end_matches('0')
450            .to_string()
451    };
452    let int_str = if int_part.is_empty() { "0" } else { &int_part };
453    let result = if frac_part.is_empty() {
454        int_str.to_string()
455    } else {
456        format!("{}.{}", int_str, frac_part)
457    };
458    normalize_decimal_number_string(&result)
459}
460
461/// 竖式取余:a mod b,返回余数字符串。约定:b 仅为非零纯整数(字符串),a 取整数部分参与运算。
462pub fn mod_decimal_str_and_normalize(a: &str, b: &str) -> String {
463    let (int_a, _) = parse_decimal_parts(a);
464    let (int_b, _) = parse_decimal_parts(b);
465    let a_digits = trim_leading_zeros(&int_a);
466    let b_digits = trim_leading_zeros(&int_b);
467    if a_digits.is_empty() {
468        return "0".to_string();
469    }
470    if b_digits.is_empty() || (b_digits.len() == 1 && b_digits[0] == 0) {
471        return "0".to_string();
472    }
473    if compare_digits(&a_digits, &b_digits) == std::cmp::Ordering::Less {
474        return digits_to_string(&a_digits);
475    }
476    let mut current: Vec<u8> = vec![];
477    for &da in &a_digits {
478        current.push(da);
479        current = trim_leading_zeros(&current);
480        let mut d = 9u8;
481        loop {
482            let product = mul_digit(&b_digits, d);
483            if compare_digits(&current, &product) != std::cmp::Ordering::Less {
484                current = sub_digits(&current, &product);
485                break;
486            }
487            if d == 0 {
488                break;
489            }
490            d -= 1;
491        }
492    }
493    normalize_decimal_number_string(&digits_to_string(&current))
494}
495
496// Non-negative integer exponent only; fractional exp => None (no exact decimal fold).
497pub fn pow_decimal_str_and_normalize(base: &str, exp: &str) -> Option<String> {
498    let (exp_int, exp_frac) = parse_decimal_parts(exp);
499    if exp_frac.iter().any(|&d| d != 0) {
500        return None;
501    }
502    let mut n = 0usize;
503    for &d in &exp_int {
504        n = n.saturating_mul(10).saturating_add(d as usize);
505    }
506    if n == 0 {
507        return Some("1".to_string());
508    }
509    let mut acc = "1".to_string();
510    let mut b = base.to_string();
511    let mut e = n;
512    while e > 0 {
513        if e % 2 == 1 {
514            acc = mul_decimal_str_and_normalize(&acc, &b);
515        }
516        b = mul_decimal_str_and_normalize(&b, &b);
517        e /= 2;
518    }
519    Some(normalize_decimal_number_string(&acc))
520}
521
522fn trim_leading_zeros(d: &[u8]) -> Vec<u8> {
523    let start = d.iter().position(|&x| x != 0).unwrap_or(d.len());
524    d[start..].to_vec()
525}
526
527/// 数字序列转字符串(高位在前)
528fn digits_to_string(d: &[u8]) -> String {
529    let t = trim_leading_zeros(d);
530    if t.is_empty() {
531        return "0".to_string();
532    }
533    t.iter().map(|&x| (b'0' + x) as char).collect()
534}
535
536/// 大数乘一位数:b * d,0 <= d <= 9,返回各位(高位在前)
537fn mul_digit(b: &[u8], d: u8) -> Vec<u8> {
538    if d == 0 {
539        return vec![0];
540    }
541    let mut b = b.to_vec();
542    b.reverse();
543    let mut carry = 0u16;
544    for x in b.iter_mut() {
545        let p = *x as u16 * d as u16 + carry;
546        *x = (p % 10) as u8;
547        carry = p / 10;
548    }
549    while carry > 0 {
550        b.push((carry % 10) as u8);
551        carry /= 10;
552    }
553    b.reverse();
554    trim_leading_zeros(&b)
555}
556
557/// 比较两个“整数”数字序列(高位在前)
558fn compare_digits(a: &[u8], b: &[u8]) -> std::cmp::Ordering {
559    let a = trim_leading_zeros(a);
560    let b = trim_leading_zeros(b);
561    if a.len() != b.len() {
562        return a.len().cmp(&b.len());
563    }
564    for (x, y) in a.iter().zip(b.iter()) {
565        if x != y {
566            return x.cmp(y);
567        }
568    }
569    std::cmp::Ordering::Equal
570}
571
572/// 大数减法:要求 a >= b,返回 a - b 的各位(高位在前)
573fn sub_digits(a: &[u8], b: &[u8]) -> Vec<u8> {
574    let mut a = a.to_vec();
575    let mut b = b.to_vec();
576    let len = a.len().max(b.len());
577    a.reverse();
578    b.reverse();
579    a.resize(len, 0);
580    b.resize(len, 0);
581    let mut borrow: i16 = 0;
582    let mut out = Vec::with_capacity(len);
583    for i in 0..len {
584        let mut d = a[i] as i16 - b[i] as i16 - borrow;
585        borrow = 0;
586        if d < 0 {
587            d += 10;
588            borrow = 1;
589        }
590        out.push(d as u8);
591    }
592    out.reverse();
593    trim_leading_zeros(&out)
594}
595
596/// 化简结果:多个负号合并(---1.1 -> -1.1)、0.0或者-0 写成 0、小数尾零去掉(1.000 -> 1)
597pub fn normalize_decimal_number_string(s: &str) -> String {
598    let s = s.trim();
599    if s.is_empty() {
600        return "0".to_string();
601    }
602    let minus_count = s.chars().take_while(|&c| c == '-').count();
603    let rest = s[minus_count..].trim();
604    let negative = (minus_count % 2) == 1;
605
606    let magnitude = if rest.contains('.') {
607        let (int_str, frac_str) = rest.split_once('.').unwrap_or((rest, ""));
608        let frac_trimmed = frac_str.trim_end_matches('0');
609        let int_trimmed = int_str.trim_start_matches('0');
610        let int_part = if int_trimmed.is_empty() || int_trimmed == "." {
611            "0"
612        } else {
613            int_trimmed
614        };
615        if frac_trimmed.is_empty() {
616            int_part.to_string()
617        } else {
618            format!("{}.{}", int_part, frac_trimmed)
619        }
620    } else {
621        let t = rest.trim_start_matches('0');
622        if t.is_empty() { "0" } else { t }.to_string()
623    };
624
625    let is_zero = magnitude == "0"
626        || (magnitude.starts_with("0.") && magnitude[2..].chars().all(|c| c == '0'));
627    if is_zero {
628        "0".to_string()
629    } else if negative {
630        format!("-{}", magnitude)
631    } else {
632        magnitude
633    }
634}
635
636/// 解析数字串为 (整数部分数字, 小数部分数字),允许 "123.45"、"123"、".5"、"0.5"
637fn parse_decimal_parts(s: &str) -> (Vec<u8>, Vec<u8>) {
638    let s = s.trim();
639    let (int_str, frac_str) = match s.find('.') {
640        Some(i) => (&s[..i], &s[i + 1..]),
641        None => (s, ""),
642    };
643    let int_digits: Vec<u8> = if int_str.is_empty() || int_str == "-" {
644        vec![0]
645    } else {
646        int_str
647            .chars()
648            .filter(|c| c.is_ascii_digit())
649            .map(|c| c as u8 - b'0')
650            .collect()
651    };
652    let frac_digits: Vec<u8> = frac_str
653        .chars()
654        .filter(|c| c.is_ascii_digit())
655        .map(|c| c as u8 - b'0')
656        .collect();
657    let int_digits = if int_digits.is_empty() {
658        vec![0]
659    } else {
660        int_digits
661    };
662    (int_digits, frac_digits)
663}