litex/rational_expression/
evaluate.rs1use 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(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(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
193fn 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
225pub 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
244pub 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
259pub 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
300pub 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
395pub 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
461pub 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(¤t);
480 let mut d = 9u8;
481 loop {
482 let product = mul_digit(&b_digits, d);
483 if compare_digits(¤t, &product) != std::cmp::Ordering::Less {
484 current = sub_digits(¤t, &product);
485 break;
486 }
487 if d == 0 {
488 break;
489 }
490 d -= 1;
491 }
492 }
493 normalize_decimal_number_string(&digits_to_string(¤t))
494}
495
496pub 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
527fn 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
536fn 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
557fn 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
572fn 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
596pub 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
636fn 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}