1use crate::{
31 error::{CoreError, CoreResult, ErrorContext},
32 numeric::precision_tracking::PrecisionContext,
33 validation::check_positive,
34};
35use num_bigint::BigInt;
36use oxinum_int::{is_prime, IBig, UBig};
38use oxinum_float::{
40 compute_e, compute_ln2, compute_pi, cos, cosh, exp, ln, precision::with_precision, sin, sinh,
41 sqrt, tan, tanh, DBig,
42};
43use oxinum_rational::{IBig as RIBig, RBig, UBig as RUBig};
45use oxinum_complex::CBig;
47use std::cmp::Ordering;
48use std::fmt;
49use std::ops::{Add, Div, Mul, Neg, Sub};
50use std::str::FromStr;
51use std::sync::RwLock;
52
53static DEFAULT_PRECISION: RwLock<u32> = RwLock::new(256);
55
56const BITS_PER_DECIMAL_DIGIT: f64 = std::f64::consts::LOG2_10;
58
59fn bits_to_decimal_digits(bits: u32) -> usize {
61 ((bits as f64) / BITS_PER_DECIMAL_DIGIT).ceil() as usize
62}
63
64fn f64_to_dbig(v: f64) -> DBig {
70 if v.is_nan() {
71 return DBig::from(0u32);
72 }
73 if v.is_infinite() {
74 return DBig::from_str("1e308").unwrap_or_else(|_| DBig::from(0u32));
76 }
77 let s = format!("{v:.17e}");
78 DBig::from_str(&s).unwrap_or_else(|_| {
79 let s2 = format!("{v}");
81 DBig::from_str(&s2).unwrap_or_else(|_| DBig::from(0u32))
82 })
83}
84
85fn dbig_to_f64(v: &DBig) -> f64 {
90 v.to_f64().value()
91}
92
93#[allow(dead_code)]
95pub fn get_defaultprecision() -> u32 {
96 *DEFAULT_PRECISION.read().expect("Operation failed")
97}
98
99#[allow(dead_code)]
101pub fn setprecision(prec: u32) -> CoreResult<()> {
102 check_positive(prec as f64, "precision")?;
103 *DEFAULT_PRECISION.write().expect("Operation failed") = prec;
104 Ok(())
105}
106
107#[derive(Debug, Clone)]
109pub struct ArbitraryPrecisionContext {
110 pub floatprecision: u32,
112 pub maxprecision: u32,
114 pub rounding_mode: RoundingMode,
116 pub trackprecision: bool,
118 pub precision_context: Option<PrecisionContext>,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
124pub enum RoundingMode {
125 Nearest,
127 Zero,
129 Up,
131 Down,
133 Away,
135}
136
137impl Default for ArbitraryPrecisionContext {
138 fn default() -> Self {
139 Self {
140 floatprecision: get_defaultprecision(),
141 maxprecision: 4096,
142 rounding_mode: RoundingMode::Nearest,
143 trackprecision: false,
144 precision_context: None,
145 }
146 }
147}
148
149impl ArbitraryPrecisionContext {
150 pub fn withprecision(precision: u32) -> CoreResult<Self> {
152 check_positive(precision as f64, "precision")?;
153 Ok(Self {
154 floatprecision: precision,
155 ..Default::default()
156 })
157 }
158
159 pub fn withprecision_tracking(precision: u32) -> CoreResult<Self> {
161 let mut ctx = Self::withprecision(precision)?;
162 ctx.trackprecision = true;
163 let mut precision_ctx = PrecisionContext::new();
164 precision_ctx.precision = precision as f64 / BITS_PER_DECIMAL_DIGIT;
165 ctx.precision_context = Some(precision_ctx);
166 Ok(ctx)
167 }
168
169 pub fn with_rounding(mut self, mode: RoundingMode) -> Self {
171 self.rounding_mode = mode;
172 self
173 }
174
175 pub fn with_maxprecision(mut self, maxprec: u32) -> Self {
177 self.maxprecision = maxprec;
178 self
179 }
180
181 fn decimal_digits(&self) -> usize {
183 bits_to_decimal_digits(self.floatprecision)
184 }
185}
186
187#[derive(Clone, PartialEq, Eq)]
193pub struct ArbitraryInt {
194 value: IBig,
195}
196
197impl ArbitraryInt {
198 pub fn new() -> Self {
200 Self {
201 value: IBig::from(0i32),
202 }
203 }
204
205 pub fn from_i64(n: i64) -> Self {
207 Self {
208 value: IBig::from(n),
209 }
210 }
211
212 pub fn from_str_radix(s: &str, radix: i32) -> CoreResult<Self> {
214 if !(2..=36).contains(&radix) {
215 return Err(CoreError::ValidationError(ErrorContext::new(format!(
216 "Invalid radix {radix}: must be 2..=36"
217 ))));
218 }
219 oxinum_int::ibig_from_radix(s, radix as u32)
220 .map(|value| Self { value })
221 .map_err(|e| {
222 CoreError::ValidationError(ErrorContext::new(format!(
223 "Failed to parse integer from string '{s}': {e}"
224 )))
225 })
226 }
227
228 pub fn to_bigint(&self) -> BigInt {
230 BigInt::from_str(&self.value.to_string()).expect("Operation failed")
231 }
232
233 pub fn is_probably_prime(&self, reps: u32) -> bool {
238 if self.value <= IBig::from(1i32) {
240 return false;
241 }
242 let s = self.value.to_string();
244 match UBig::from_str(&s) {
245 Ok(u) => is_prime(&u, reps),
246 Err(_) => false,
247 }
248 }
249
250 pub fn factorial(n: u32) -> Self {
252 let u = oxinum_int::factorial(n);
253 Self {
254 value: IBig::from(u),
255 }
256 }
257
258 pub fn binomial(n: u32, k: u32) -> Self {
260 if k > n {
261 return Self::new();
262 }
263 let u = oxinum_int::binomial(n, k);
264 Self {
265 value: IBig::from(u),
266 }
267 }
268
269 pub fn gcd(&self, other: &Self) -> Self {
271 use oxinum_int::Gcd;
272 let a = self.value.clone();
274 let b = other.value.clone();
275 let g: UBig = a.gcd(&b);
276 Self {
277 value: IBig::from(g),
278 }
279 }
280
281 pub fn lcm(&self, other: &Self) -> Self {
283 if self.value == IBig::from(0i32) || other.value == IBig::from(0i32) {
284 return Self::new();
285 }
286 let gcd = self.gcd(other);
287 let product = self.value.clone() * other.value.clone();
288 Self {
289 value: product / gcd.value,
290 }
291 }
292
293 pub fn mod_pow(&self, exp: &Self, modulus: &Self) -> CoreResult<Self> {
295 if modulus.value == IBig::from(0i32) {
296 return Err(CoreError::DomainError(ErrorContext::new(
297 "Modulus cannot be zero",
298 )));
299 }
300 let base_str = self.value.to_string();
302 let exp_str = exp.value.to_string();
303 let mod_str = modulus.value.to_string();
304 let base_u = UBig::from_str(&base_str).map_err(|_| {
305 CoreError::DomainError(ErrorContext::new("base must be non-negative for mod_pow"))
306 })?;
307 let exp_u = UBig::from_str(&exp_str).map_err(|_| {
308 CoreError::DomainError(ErrorContext::new(
309 "exponent must be non-negative for mod_pow",
310 ))
311 })?;
312 let mod_u = UBig::from_str(&mod_str).map_err(|_| {
313 CoreError::DomainError(ErrorContext::new(
314 "modulus must be non-negative for mod_pow",
315 ))
316 })?;
317 let result = oxinum_int::mod_pow(&base_u, &exp_u, &mod_u)
318 .map_err(|e| CoreError::DomainError(ErrorContext::new(format!("{e}"))))?;
319 Ok(Self {
320 value: IBig::from(result),
321 })
322 }
323
324 pub fn abs(&self) -> Self {
326 use oxinum_core::Abs;
327 Self {
328 value: self.value.clone().abs(),
329 }
330 }
331
332 pub fn signum(&self) -> i32 {
334 use oxinum_core::Signed;
335 if self.value == IBig::from(0i32) {
338 return 0;
339 }
340 match self.value.sign() {
341 oxinum_core::Sign::Positive => 1,
342 oxinum_core::Sign::Negative => -1,
343 }
344 }
345}
346
347impl fmt::Display for ArbitraryInt {
348 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349 write!(f, "{}", self.value)
350 }
351}
352
353impl fmt::Debug for ArbitraryInt {
354 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355 write!(f, "ArbitraryInt({})", self.value)
356 }
357}
358
359impl Default for ArbitraryInt {
360 fn default() -> Self {
361 Self::new()
362 }
363}
364
365impl Add for ArbitraryInt {
366 type Output = Self;
367 fn add(self, rhs: Self) -> Self::Output {
368 Self {
369 value: self.value + rhs.value,
370 }
371 }
372}
373
374impl Sub for ArbitraryInt {
375 type Output = Self;
376 fn sub(self, rhs: Self) -> Self::Output {
377 Self {
378 value: self.value - rhs.value,
379 }
380 }
381}
382
383impl Mul for ArbitraryInt {
384 type Output = Self;
385 fn mul(self, rhs: Self) -> Self::Output {
386 Self {
387 value: self.value * rhs.value,
388 }
389 }
390}
391
392impl Div for ArbitraryInt {
393 type Output = Self;
394 fn div(self, rhs: Self) -> Self::Output {
395 Self {
396 value: self.value / rhs.value,
397 }
398 }
399}
400
401impl Neg for ArbitraryInt {
402 type Output = Self;
403 fn neg(self) -> Self::Output {
404 Self { value: -self.value }
405 }
406}
407
408#[derive(Clone)]
418pub struct ArbitraryFloat {
419 value: DBig,
420 context: ArbitraryPrecisionContext,
421}
422
423impl ArbitraryFloat {
424 pub fn new() -> Self {
426 let prec = get_defaultprecision();
427 let context = ArbitraryPrecisionContext::default();
428 let digits = bits_to_decimal_digits(prec);
429 let value = with_precision(&DBig::from(0u32), digits);
430 Self { value, context }
431 }
432
433 pub fn withprecision(prec: u32) -> CoreResult<Self> {
435 let context = ArbitraryPrecisionContext::withprecision(prec)?;
436 let digits = bits_to_decimal_digits(prec);
437 let value = with_precision(&DBig::from(0u32), digits);
438 Ok(Self { value, context })
439 }
440
441 pub fn with_context(context: ArbitraryPrecisionContext) -> Self {
443 let digits = context.decimal_digits();
444 let value = with_precision(&DBig::from(0u32), digits);
445 Self { value, context }
446 }
447
448 pub fn from_f64(v: f64) -> Self {
450 let prec = get_defaultprecision();
451 let context = ArbitraryPrecisionContext::default();
452 let digits = bits_to_decimal_digits(prec);
453 let raw = f64_to_dbig(v);
454 let value = with_precision(&raw, digits);
455 Self { value, context }
456 }
457
458 pub fn from_f64_withprecision(v: f64, prec: u32) -> CoreResult<Self> {
460 let context = ArbitraryPrecisionContext::withprecision(prec)?;
461 let digits = bits_to_decimal_digits(prec);
462 let raw = f64_to_dbig(v);
463 let value = with_precision(&raw, digits);
464 Ok(Self { value, context })
465 }
466
467 pub fn from_strprec(s: &str, prec: u32) -> CoreResult<Self> {
469 let context = ArbitraryPrecisionContext::withprecision(prec)?;
470 let digits = bits_to_decimal_digits(prec);
471 let parsed = DBig::from_str(s)
472 .map_err(|e| CoreError::ValidationError(ErrorContext::new(format!("{e}"))))?;
473 let value = with_precision(&parsed, digits);
474 Ok(Self { value, context })
475 }
476
477 pub fn precision(&self) -> u32 {
479 self.context.floatprecision
480 }
481
482 pub fn decimalprecision(&self) -> u32 {
484 self.context.decimal_digits() as u32
485 }
486
487 pub fn setprecision(&self, prec: u32) -> CoreResult<Self> {
489 let mut context = self.context.clone();
490 context.floatprecision = prec;
491 let digits = bits_to_decimal_digits(prec);
492 let value = with_precision(&self.value, digits);
493 Ok(Self { value, context })
494 }
495
496 pub fn to_f64(&self) -> f64 {
498 dbig_to_f64(&self.value)
499 }
500
501 pub fn is_finite(&self) -> bool {
503 true
504 }
505
506 pub fn is_infinite(&self) -> bool {
508 false
509 }
510
511 pub fn is_nan(&self) -> bool {
513 false
514 }
515
516 pub fn is_zero(&self) -> bool {
518 self.value == DBig::from(0u32)
519 }
520
521 pub fn abs(&self) -> Self {
523 use oxinum_core::Abs;
524 Self {
525 value: self.value.clone().abs(),
526 context: self.context.clone(),
527 }
528 }
529
530 pub fn sqrt(&self) -> CoreResult<Self> {
532 let zero = DBig::from(0u32);
533 if self.value < zero {
534 return Err(CoreError::DomainError(ErrorContext::new(
535 "Square root of negative number",
536 )));
537 }
538 let digits = self.context.decimal_digits();
539 let result = sqrt(&self.value, digits)
540 .map_err(|e| CoreError::DomainError(ErrorContext::new(format!("{e}"))))?;
541 Ok(Self {
542 value: result,
543 context: self.context.clone(),
544 })
545 }
546
547 pub fn ln(&self) -> CoreResult<Self> {
549 let zero = DBig::from(0u32);
550 if self.value <= zero {
551 return Err(CoreError::DomainError(ErrorContext::new(
552 "Logarithm of non-positive number",
553 )));
554 }
555 let digits = self.context.decimal_digits();
556 let result = ln(&self.value, digits)
557 .map_err(|e| CoreError::DomainError(ErrorContext::new(format!("{e}"))))?;
558 Ok(Self {
559 value: result,
560 context: self.context.clone(),
561 })
562 }
563
564 pub fn exp(&self) -> Self {
566 let digits = self.context.decimal_digits();
567 let result = exp(&self.value, digits).unwrap_or_else(|_| DBig::from(1u32));
568 Self {
569 value: result,
570 context: self.context.clone(),
571 }
572 }
573
574 pub fn pow(&self, exponent: &Self) -> Self {
576 use oxinum_float::pow as oxinum_pow;
577 let digits = self.context.decimal_digits();
578 let result =
579 oxinum_pow(&self.value, &exponent.value, digits).unwrap_or_else(|_| DBig::from(1u32));
580 Self {
581 value: result,
582 context: self.context.clone(),
583 }
584 }
585
586 pub fn sin(&self) -> Self {
588 let digits = self.context.decimal_digits();
589 let result = sin(&self.value, digits).unwrap_or_else(|_| DBig::from(0u32));
590 Self {
591 value: result,
592 context: self.context.clone(),
593 }
594 }
595
596 pub fn cos(&self) -> Self {
598 let digits = self.context.decimal_digits();
599 let result = cos(&self.value, digits).unwrap_or_else(|_| DBig::from(1u32));
600 Self {
601 value: result,
602 context: self.context.clone(),
603 }
604 }
605
606 pub fn tan(&self) -> Self {
608 let digits = self.context.decimal_digits();
609 let result = tan(&self.value, digits).unwrap_or_else(|_| DBig::from(0u32));
610 Self {
611 value: result,
612 context: self.context.clone(),
613 }
614 }
615
616 pub fn asin(&self) -> CoreResult<Self> {
618 let one = DBig::from(1u32);
620 let abs_val = {
621 use oxinum_core::Abs;
622 self.value.clone().abs()
623 };
624 if abs_val > one {
625 return Err(CoreError::DomainError(ErrorContext::new(
626 "Arcsine argument out of range [-1, 1]",
627 )));
628 }
629 let digits = self.context.decimal_digits();
632 let one_minus_x2 = {
633 let x2 = self.value.clone() * self.value.clone();
634 DBig::from(1u32) - x2
635 };
636 let denom = sqrt(&one_minus_x2, digits + 4)
637 .map_err(|e| CoreError::DomainError(ErrorContext::new(format!("{e}"))))?;
638 let zero = DBig::from(0u32);
639 if denom == zero {
640 let pi = compute_pi(digits);
642 let two = DBig::from(2u32);
643 let half_pi = pi / two;
644 let result = if self.value < zero { -half_pi } else { half_pi };
646 return Ok(Self {
647 value: result,
648 context: self.context.clone(),
649 });
650 }
651 let ratio = self.value.clone() / denom;
652 use oxinum_float::atan as oxinum_atan;
653 let result = oxinum_atan(&ratio, digits)
654 .map_err(|e| CoreError::DomainError(ErrorContext::new(format!("{e}"))))?;
655 Ok(Self {
656 value: result,
657 context: self.context.clone(),
658 })
659 }
660
661 pub fn acos(&self) -> CoreResult<Self> {
663 let one = DBig::from(1u32);
665 let abs_val = {
666 use oxinum_core::Abs;
667 self.value.clone().abs()
668 };
669 if abs_val > one {
670 return Err(CoreError::DomainError(ErrorContext::new(
671 "Arccosine argument out of range [-1, 1]",
672 )));
673 }
674 let digits = self.context.decimal_digits();
675 let pi = compute_pi(digits + 4);
676 let two = DBig::from(2u32);
677 let half_pi = pi / two;
678 let asin_val = self.asin()?;
679 Ok(Self {
680 value: half_pi - asin_val.value,
681 context: self.context.clone(),
682 })
683 }
684
685 pub fn atan(&self) -> Self {
687 use oxinum_float::atan as oxinum_atan;
688 let digits = self.context.decimal_digits();
689 let result = oxinum_atan(&self.value, digits).unwrap_or_else(|_| DBig::from(0u32));
690 Self {
691 value: result,
692 context: self.context.clone(),
693 }
694 }
695
696 pub fn atan2(&self, x: &Self) -> Self {
698 use oxinum_float::atan2 as oxinum_atan2;
699 let digits = self.context.decimal_digits();
700 let result =
701 oxinum_atan2(&self.value, &x.value, digits).unwrap_or_else(|_| DBig::from(0u32));
702 Self {
703 value: result,
704 context: self.context.clone(),
705 }
706 }
707
708 pub fn sinh(&self) -> Self {
710 let digits = self.context.decimal_digits();
711 let result = sinh(&self.value, digits).unwrap_or_else(|_| DBig::from(0u32));
712 Self {
713 value: result,
714 context: self.context.clone(),
715 }
716 }
717
718 pub fn cosh(&self) -> Self {
720 let digits = self.context.decimal_digits();
721 let result = cosh(&self.value, digits).unwrap_or_else(|_| DBig::from(1u32));
722 Self {
723 value: result,
724 context: self.context.clone(),
725 }
726 }
727
728 pub fn tanh(&self) -> Self {
730 let digits = self.context.decimal_digits();
731 let result = tanh(&self.value, digits).unwrap_or_else(|_| DBig::from(0u32));
732 Self {
733 value: result,
734 context: self.context.clone(),
735 }
736 }
737
738 pub fn prec_2(prec: u32) -> CoreResult<Self> {
744 let context = ArbitraryPrecisionContext::withprecision(prec)?;
745 let digits = bits_to_decimal_digits(prec);
746 let value = with_precision(&compute_pi(digits), digits);
747 Ok(Self { value, context })
748 }
749
750 pub fn prec_3(prec: u32) -> CoreResult<Self> {
752 let context = ArbitraryPrecisionContext::withprecision(prec)?;
753 let digits = bits_to_decimal_digits(prec);
754 let value = with_precision(&compute_e(digits), digits);
755 Ok(Self { value, context })
756 }
757
758 pub fn prec_4(prec: u32) -> CoreResult<Self> {
760 let context = ArbitraryPrecisionContext::withprecision(prec)?;
761 let digits = bits_to_decimal_digits(prec);
762 let value = with_precision(&compute_ln2(digits), digits);
763 Ok(Self { value, context })
764 }
765}
766
767impl fmt::Display for ArbitraryFloat {
768 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
769 write!(f, "{}", self.value)
770 }
771}
772
773impl fmt::Debug for ArbitraryFloat {
774 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
775 write!(
776 f,
777 "ArbitraryFloat({}, {} bits)",
778 self.value,
779 self.precision()
780 )
781 }
782}
783
784impl PartialEq for ArbitraryFloat {
785 fn eq(&self, other: &Self) -> bool {
786 self.value == other.value
787 }
788}
789
790impl PartialOrd for ArbitraryFloat {
791 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
792 self.value.partial_cmp(&other.value)
793 }
794}
795
796impl Default for ArbitraryFloat {
797 fn default() -> Self {
798 Self::new()
799 }
800}
801
802impl Add for ArbitraryFloat {
803 type Output = Self;
804 fn add(self, rhs: Self) -> Self::Output {
805 Self {
806 value: self.value + rhs.value,
807 context: self.context,
808 }
809 }
810}
811
812impl Sub for ArbitraryFloat {
813 type Output = Self;
814 fn sub(self, rhs: Self) -> Self::Output {
815 Self {
816 value: self.value - rhs.value,
817 context: self.context,
818 }
819 }
820}
821
822impl Mul for ArbitraryFloat {
823 type Output = Self;
824 fn mul(self, rhs: Self) -> Self::Output {
825 Self {
826 value: self.value * rhs.value,
827 context: self.context,
828 }
829 }
830}
831
832impl Div for ArbitraryFloat {
833 type Output = Self;
834 fn div(self, rhs: Self) -> Self::Output {
835 Self {
836 value: self.value / rhs.value,
837 context: self.context,
838 }
839 }
840}
841
842impl Neg for ArbitraryFloat {
843 type Output = Self;
844 fn neg(self) -> Self::Output {
845 Self {
846 value: -self.value,
847 context: self.context,
848 }
849 }
850}
851
852#[derive(Clone, PartialEq, Eq)]
858pub struct ArbitraryRational {
859 value: RBig,
860}
861
862impl ArbitraryRational {
863 pub fn new() -> Self {
865 Self {
866 value: RBig::from(0u32),
867 }
868 }
869
870 pub fn num(num: i64, den: i64) -> CoreResult<Self> {
872 if den == 0 {
873 return Err(CoreError::DomainError(ErrorContext::new(
874 "Denominator cannot be zero",
875 )));
876 }
877 let n = RIBig::from(num);
878 let d = RUBig::from(den.unsigned_abs());
879 let signed_n = if den < 0 { -n } else { n };
880 Ok(Self {
881 value: RBig::from_parts(signed_n, d),
882 })
883 }
884
885 pub fn num_2(num: &ArbitraryInt, den: &ArbitraryInt) -> CoreResult<Self> {
887 if den.value == IBig::from(0i32) {
888 return Err(CoreError::DomainError(ErrorContext::new(
889 "Denominator cannot be zero",
890 )));
891 }
892 let n = RIBig::from_str(&num.value.to_string()).map_err(|_| {
893 CoreError::ValidationError(ErrorContext::new("numerator conversion failed"))
894 })?;
895 let d_ibig = IBig::from_str(&den.value.to_string()).map_err(|_| {
896 CoreError::ValidationError(ErrorContext::new("denominator conversion failed"))
897 })?;
898 use oxinum_core::Abs;
900 let (n_final, d_ubig) = if d_ibig < IBig::from(0i32) {
901 let neg_n = RIBig::from_str(&(-num.value.clone()).to_string())
902 .unwrap_or_else(|_| RIBig::from(0i32));
903 let d_abs = RUBig::from_str(&d_ibig.clone().abs().to_string()).unwrap_or(RUBig::ONE);
904 (neg_n, d_abs)
905 } else {
906 let d_abs = RUBig::from_str(&d_ibig.to_string()).unwrap_or(RUBig::ONE);
907 (n, d_abs)
908 };
909 Ok(Self {
910 value: RBig::from_parts(n_final, d_ubig),
911 })
912 }
913
914 #[deprecated(since = "0.1.0", note = "Use str::parse() instead")]
916 pub fn parse_rational(s: &str) -> CoreResult<Self> {
917 s.parse()
918 }
919
920 pub fn to_f64(&self) -> f64 {
922 use oxinum_rational::to_f64 as rbig_to_f64;
923 rbig_to_f64(&self.value)
924 }
925
926 pub fn to_arbitrary_float(&self, prec: u32) -> CoreResult<ArbitraryFloat> {
928 let context = ArbitraryPrecisionContext::withprecision(prec)?;
929 let digits = bits_to_decimal_digits(prec);
930 let num_str = self.value.numerator().to_string();
932 let den_str = self.value.denominator().to_string();
933 let n = DBig::from_str(&num_str)
934 .map_err(|e| CoreError::ValidationError(ErrorContext::new(format!("{e}"))))?;
935 let d = DBig::from_str(&den_str)
936 .map_err(|e| CoreError::ValidationError(ErrorContext::new(format!("{e}"))))?;
937 let n_prec = with_precision(&n, digits + 4);
938 let d_prec = with_precision(&d, digits + 4);
939 let value = with_precision(&(n_prec / d_prec), digits);
940 Ok(ArbitraryFloat { value, context })
941 }
942
943 pub fn numerator(&self) -> ArbitraryInt {
945 let n_str = self.value.numerator().to_string();
946 let v = IBig::from_str(&n_str).unwrap_or_else(|_| IBig::from(0i32));
947 ArbitraryInt { value: v }
948 }
949
950 pub fn denominator(&self) -> ArbitraryInt {
952 let d_str = self.value.denominator().to_string();
953 let v = IBig::from_str(&d_str).unwrap_or_else(|_| IBig::from(1i32));
954 ArbitraryInt { value: v }
955 }
956
957 pub fn abs(&self) -> Self {
959 use oxinum_rational::rational_abs;
960 Self {
961 value: rational_abs(&self.value),
962 }
963 }
964
965 pub fn recip(&self) -> CoreResult<Self> {
967 if self.value == RBig::from(0u32) {
968 return Err(CoreError::DomainError(ErrorContext::new(
969 "Cannot take reciprocal of zero",
970 )));
971 }
972 use oxinum_rational::rational_reciprocal;
973 let recip = rational_reciprocal(&self.value)
974 .map_err(|e| CoreError::DomainError(ErrorContext::new(format!("{e}"))))?;
975 Ok(Self { value: recip })
976 }
977}
978
979impl fmt::Display for ArbitraryRational {
980 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
981 write!(f, "{}", self.value)
982 }
983}
984
985impl fmt::Debug for ArbitraryRational {
986 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
987 write!(f, "ArbitraryRational({})", self.value)
988 }
989}
990
991impl Default for ArbitraryRational {
992 fn default() -> Self {
993 Self::new()
994 }
995}
996
997impl FromStr for ArbitraryRational {
998 type Err = CoreError;
999
1000 fn from_str(s: &str) -> Result<Self, Self::Err> {
1001 if let Some(slash) = s.find('/') {
1003 let num_s = &s[..slash];
1004 let den_s = &s[slash + 1..];
1005 let n = RIBig::from_str(num_s.trim()).map_err(|_| {
1006 CoreError::ValidationError(ErrorContext::new(format!(
1007 "Failed to parse rational from string: {s}"
1008 )))
1009 })?;
1010 let d = RUBig::from_str(den_s.trim()).map_err(|_| {
1011 CoreError::ValidationError(ErrorContext::new(format!(
1012 "Failed to parse rational from string: {s}"
1013 )))
1014 })?;
1015 return Ok(Self {
1016 value: RBig::from_parts(n, d),
1017 });
1018 }
1019 let n = RIBig::from_str(s.trim()).map_err(|_| {
1021 CoreError::ValidationError(ErrorContext::new(format!(
1022 "Failed to parse rational from string: {s}"
1023 )))
1024 })?;
1025 Ok(Self {
1026 value: RBig::from_parts(n, RUBig::ONE),
1027 })
1028 }
1029}
1030
1031impl Add for ArbitraryRational {
1032 type Output = Self;
1033 fn add(self, rhs: Self) -> Self::Output {
1034 Self {
1035 value: self.value + rhs.value,
1036 }
1037 }
1038}
1039
1040impl Sub for ArbitraryRational {
1041 type Output = Self;
1042 fn sub(self, rhs: Self) -> Self::Output {
1043 Self {
1044 value: self.value - rhs.value,
1045 }
1046 }
1047}
1048
1049impl Mul for ArbitraryRational {
1050 type Output = Self;
1051 fn mul(self, rhs: Self) -> Self::Output {
1052 Self {
1053 value: self.value * rhs.value,
1054 }
1055 }
1056}
1057
1058impl Div for ArbitraryRational {
1059 type Output = Self;
1060 fn div(self, rhs: Self) -> Self::Output {
1061 Self {
1062 value: self.value / rhs.value,
1063 }
1064 }
1065}
1066
1067impl Neg for ArbitraryRational {
1068 type Output = Self;
1069 fn neg(self) -> Self::Output {
1070 Self { value: -self.value }
1071 }
1072}
1073
1074#[derive(Clone)]
1084pub struct ArbitraryComplex {
1085 value: CBig,
1086 context: ArbitraryPrecisionContext,
1087}
1088
1089impl ArbitraryComplex {
1090 fn prec_digits(&self) -> usize {
1093 bits_to_decimal_digits(self.context.floatprecision)
1094 }
1095
1096 pub fn new() -> Self {
1098 Self {
1099 value: CBig::zero(),
1100 context: ArbitraryPrecisionContext::default(),
1101 }
1102 }
1103
1104 pub fn prec(prec: u32) -> CoreResult<Self> {
1106 let context = ArbitraryPrecisionContext::withprecision(prec)?;
1107 Ok(Self {
1108 value: CBig::zero(),
1109 context,
1110 })
1111 }
1112
1113 pub fn re(re: &ArbitraryFloat, im: &ArbitraryFloat) -> Self {
1115 let prec = re.precision().max(im.precision());
1116 let context = re.context.clone();
1117 let re_f = re.to_f64();
1118 let im_f = im.to_f64();
1119 let value = CBig::from_f64(re_f, im_f).unwrap_or_else(|_| CBig::zero());
1121 Self {
1122 value,
1123 context: ArbitraryPrecisionContext {
1124 floatprecision: prec,
1125 ..context
1126 },
1127 }
1128 }
1129
1130 pub fn re_2(re: f64, im: f64) -> Self {
1132 let value = CBig::from_f64(re, im).unwrap_or_else(|_| CBig::zero());
1133 Self {
1134 value,
1135 context: ArbitraryPrecisionContext::default(),
1136 }
1137 }
1138
1139 pub fn real(&self) -> ArbitraryFloat {
1141 let (re_f64, _) = self.value.to_f64_parts();
1142 ArbitraryFloat::from_f64(re_f64)
1143 }
1144
1145 pub fn imag(&self) -> ArbitraryFloat {
1147 let (_, im_f64) = self.value.to_f64_parts();
1148 ArbitraryFloat::from_f64(im_f64)
1149 }
1150
1151 pub fn abs(&self) -> ArbitraryFloat {
1153 let digits = self.prec_digits();
1154 let mag_f64 = self
1155 .value
1156 .abs(digits)
1157 .map(|d| d.to_f64().value())
1158 .unwrap_or(0.0);
1159 ArbitraryFloat::from_f64(mag_f64)
1160 }
1161
1162 pub fn arg(&self) -> ArbitraryFloat {
1164 let digits = self.prec_digits();
1165 let arg_f64 = self
1166 .value
1167 .arg(digits)
1168 .map(|d| d.to_f64().value())
1169 .unwrap_or(0.0);
1170 ArbitraryFloat::from_f64(arg_f64)
1171 }
1172
1173 pub fn conj(&self) -> Self {
1175 Self {
1176 value: self.value.conj(),
1177 context: self.context.clone(),
1178 }
1179 }
1180
1181 pub fn ln(&self) -> Self {
1186 let digits = self.prec_digits();
1187 let value = self.value.ln(digits).unwrap_or_else(|_| CBig::zero());
1188 Self {
1189 value,
1190 context: self.context.clone(),
1191 }
1192 }
1193
1194 pub fn exp(&self) -> Self {
1196 let digits = self.prec_digits();
1197 let value = self.value.exp(digits).unwrap_or_else(|_| CBig::zero());
1198 Self {
1199 value,
1200 context: self.context.clone(),
1201 }
1202 }
1203
1204 pub fn pow(&self, exp: &Self) -> Self {
1208 let digits = self.prec_digits();
1209 let value = self
1210 .value
1211 .pow(&exp.value, digits)
1212 .unwrap_or_else(|_| CBig::zero());
1213 Self {
1214 value,
1215 context: self.context.clone(),
1216 }
1217 }
1218
1219 pub fn sqrt(&self) -> Self {
1221 let digits = self.prec_digits();
1222 let value = self.value.sqrt(digits).unwrap_or_else(|_| CBig::zero());
1223 Self {
1224 value,
1225 context: self.context.clone(),
1226 }
1227 }
1228}
1229
1230impl fmt::Display for ArbitraryComplex {
1231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1232 let (re, im) = self.value.to_f64_parts();
1233 if im >= 0.0 {
1234 write!(f, "{} + {}i", re, im)
1235 } else {
1236 write!(f, "{} - {}i", re, -im)
1237 }
1238 }
1239}
1240
1241impl fmt::Debug for ArbitraryComplex {
1242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1243 write!(
1244 f,
1245 "ArbitraryComplex({}, {} bits)",
1246 self, self.context.floatprecision
1247 )
1248 }
1249}
1250
1251impl PartialEq for ArbitraryComplex {
1252 fn eq(&self, other: &Self) -> bool {
1253 self.value == other.value
1254 }
1255}
1256
1257impl Default for ArbitraryComplex {
1258 fn default() -> Self {
1259 Self::new()
1260 }
1261}
1262
1263impl Add for ArbitraryComplex {
1264 type Output = Self;
1265 fn add(self, rhs: Self) -> Self::Output {
1266 Self {
1267 value: self.value + rhs.value,
1268 context: self.context,
1269 }
1270 }
1271}
1272
1273impl Sub for ArbitraryComplex {
1274 type Output = Self;
1275 fn sub(self, rhs: Self) -> Self::Output {
1276 Self {
1277 value: self.value - rhs.value,
1278 context: self.context,
1279 }
1280 }
1281}
1282
1283impl Mul for ArbitraryComplex {
1284 type Output = Self;
1285 fn mul(self, rhs: Self) -> Self::Output {
1286 Self {
1287 value: self.value * rhs.value,
1288 context: self.context,
1289 }
1290 }
1291}
1292
1293impl Div for ArbitraryComplex {
1294 type Output = Self;
1295 fn div(self, rhs: Self) -> Self::Output {
1296 Self {
1297 value: self.value / rhs.value,
1298 context: self.context,
1299 }
1300 }
1301}
1302
1303impl Neg for ArbitraryComplex {
1304 type Output = Self;
1305 fn neg(self) -> Self::Output {
1306 Self {
1307 value: -self.value,
1308 context: self.context,
1309 }
1310 }
1311}
1312
1313pub trait ToArbitraryPrecision {
1319 type ArbitraryType;
1321
1322 fn to_arbitrary(&self) -> Self::ArbitraryType;
1324
1325 fn to_arbitraryprec(&self, prec: u32) -> CoreResult<Self::ArbitraryType>;
1327}
1328
1329impl ToArbitraryPrecision for i32 {
1330 type ArbitraryType = ArbitraryInt;
1331
1332 fn to_arbitrary(&self) -> Self::ArbitraryType {
1333 ArbitraryInt::from_i64(*self as i64)
1334 }
1335
1336 fn to_arbitraryprec(&self, _prec: u32) -> CoreResult<Self::ArbitraryType> {
1337 Ok(self.to_arbitrary())
1338 }
1339}
1340
1341impl ToArbitraryPrecision for i64 {
1342 type ArbitraryType = ArbitraryInt;
1343
1344 fn to_arbitrary(&self) -> Self::ArbitraryType {
1345 ArbitraryInt::from_i64(*self)
1346 }
1347
1348 fn to_arbitraryprec(&self, _prec: u32) -> CoreResult<Self::ArbitraryType> {
1349 Ok(self.to_arbitrary())
1350 }
1351}
1352
1353impl ToArbitraryPrecision for f32 {
1354 type ArbitraryType = ArbitraryFloat;
1355
1356 fn to_arbitrary(&self) -> Self::ArbitraryType {
1357 ArbitraryFloat::from_f64(*self as f64)
1358 }
1359
1360 fn to_arbitraryprec(&self, prec: u32) -> CoreResult<Self::ArbitraryType> {
1361 ArbitraryFloat::from_f64_withprecision(*self as f64, prec)
1362 }
1363}
1364
1365impl ToArbitraryPrecision for f64 {
1366 type ArbitraryType = ArbitraryFloat;
1367
1368 fn to_arbitrary(&self) -> Self::ArbitraryType {
1369 ArbitraryFloat::from_f64(*self)
1370 }
1371
1372 fn to_arbitraryprec(&self, prec: u32) -> CoreResult<Self::ArbitraryType> {
1373 ArbitraryFloat::from_f64_withprecision(*self, prec)
1374 }
1375}
1376
1377pub struct ArbitraryPrecisionBuilder {
1383 context: ArbitraryPrecisionContext,
1384}
1385
1386impl ArbitraryPrecisionBuilder {
1387 pub fn new() -> Self {
1389 Self {
1390 context: ArbitraryPrecisionContext::default(),
1391 }
1392 }
1393
1394 pub fn precision(mut self, prec: u32) -> Self {
1396 self.context.floatprecision = prec;
1397 self
1398 }
1399
1400 pub fn decimalprecision(mut self, digits: u32) -> Self {
1402 self.context.floatprecision = ((digits as f64) * BITS_PER_DECIMAL_DIGIT) as u32;
1403 self
1404 }
1405
1406 pub fn rounding(mut self, mode: RoundingMode) -> Self {
1408 self.context.rounding_mode = mode;
1409 self
1410 }
1411
1412 pub fn trackprecision(mut self, track: bool) -> Self {
1414 self.context.trackprecision = track;
1415 if track && self.context.precision_context.is_none() {
1416 let mut precision_ctx = PrecisionContext::new();
1417 precision_ctx.precision = self.context.floatprecision as f64 / BITS_PER_DECIMAL_DIGIT;
1418 self.context.precision_context = Some(precision_ctx);
1419 }
1420 self
1421 }
1422
1423 pub fn build_float(self) -> ArbitraryFloat {
1425 ArbitraryFloat::with_context(self.context)
1426 }
1427
1428 pub fn build_complex(self) -> CoreResult<ArbitraryComplex> {
1430 ArbitraryComplex::prec(self.context.floatprecision)
1431 }
1432
1433 pub fn calculate<F, R>(self, f: F) -> R
1435 where
1436 F: FnOnce(&ArbitraryPrecisionContext) -> R,
1437 {
1438 f(&self.context)
1439 }
1440}
1441
1442impl Default for ArbitraryPrecisionBuilder {
1443 fn default() -> Self {
1444 Self::new()
1445 }
1446}
1447
1448pub mod utils {
1454 use super::*;
1455
1456 pub fn pi(prec: u32) -> CoreResult<ArbitraryFloat> {
1458 ArbitraryFloat::prec_2(prec)
1459 }
1460
1461 pub fn e(prec: u32) -> CoreResult<ArbitraryFloat> {
1463 ArbitraryFloat::prec_3(prec)
1464 }
1465
1466 pub fn ln2(prec: u32) -> CoreResult<ArbitraryFloat> {
1468 ArbitraryFloat::prec_4(prec)
1469 }
1470
1471 pub fn sqrt2(prec: u32) -> CoreResult<ArbitraryFloat> {
1473 let two = ArbitraryFloat::from_f64_withprecision(2.0, prec)?;
1474 two.sqrt()
1475 }
1476
1477 pub fn golden_ratio(prec: u32) -> CoreResult<ArbitraryFloat> {
1479 let one = ArbitraryFloat::from_f64_withprecision(1.0, prec)?;
1480 let five = ArbitraryFloat::from_f64_withprecision(5.0, prec)?;
1481 let sqrt5 = five.sqrt()?;
1482 let two = ArbitraryFloat::from_f64_withprecision(2.0, prec)?;
1483 Ok((one + sqrt5) / two)
1484 }
1485
1486 pub fn factorial(n: u32) -> ArbitraryInt {
1488 ArbitraryInt::factorial(n)
1489 }
1490
1491 pub fn binomial(n: u32, k: u32) -> ArbitraryInt {
1493 ArbitraryInt::binomial(n, k)
1494 }
1495
1496 pub fn is_probably_prime(n: &ArbitraryInt, certainty: u32) -> bool {
1498 n.is_probably_prime(certainty)
1499 }
1500}
1501
1502#[cfg(test)]
1507mod tests {
1508 use super::*;
1509
1510 #[test]
1511 fn test_arbitrary_int_basic() {
1512 let a = ArbitraryInt::from_i64(123);
1513 let b = ArbitraryInt::from_i64(456);
1514 let sum = a.clone() + b.clone();
1515 assert_eq!(sum.to_string(), "579");
1516
1517 let product = a.clone() * b.clone();
1518 assert_eq!(product.to_string(), "56088");
1519
1520 let factorial = ArbitraryInt::factorial(20);
1521 assert_eq!(factorial.to_string(), "2432902008176640000");
1522 }
1523
1524 #[test]
1525 fn test_arbitrary_float_basic() {
1526 let a = ArbitraryFloat::from_f64_withprecision(1.0, 128).expect("Operation failed");
1527 let b = ArbitraryFloat::from_f64_withprecision(3.0, 128).expect("Operation failed");
1528 let c = a / b;
1529
1530 let c_str = c.to_string();
1532 assert!(
1534 c_str.starts_with("3.333333333333333") || c_str.starts_with("0.333333333333333"),
1535 "unexpected value: {c_str}"
1536 );
1537 assert!(c_str.len() > 10, "result too short: {c_str}");
1538 }
1539
1540 #[test]
1541 fn test_arbitrary_rational() {
1542 let r = ArbitraryRational::num(22, 7).expect("Operation failed");
1543 assert_eq!(r.to_string(), "22/7");
1544
1545 let a = ArbitraryRational::num(1, 3).expect("Operation failed");
1546 let b = ArbitraryRational::num(1, 6).expect("Operation failed");
1547 let sum = a + b;
1548 assert_eq!(sum.to_string(), "1/2");
1549 }
1550
1551 #[test]
1552 fn test_arbitrary_complex() {
1553 let z = ArbitraryComplex::re_2(3.0, 4.0);
1554 let mag = z.abs();
1555 assert!((mag.to_f64() - 5.0).abs() < 1e-10);
1556
1557 let conj = z.conj();
1558 assert_eq!(conj.real().to_f64(), 3.0);
1559 assert_eq!(conj.imag().to_f64(), -4.0);
1560 }
1561
1562 #[test]
1563 fn testprecision_builder() {
1564 let x = ArbitraryPrecisionBuilder::new()
1565 .decimalprecision(50)
1566 .rounding(RoundingMode::Nearest)
1567 .build_float();
1568
1569 assert!(x.decimalprecision() >= 49); }
1571
1572 #[test]
1573 fn test_constants() {
1574 let pi = utils::pi(256).expect("Operation failed");
1575 let pi_str = pi.to_string();
1576 assert!(pi_str.starts_with("3.14159265358979"), "pi = {pi_str}");
1577
1578 let e = utils::e(256).expect("Operation failed");
1579 let e_str = e.to_string();
1580 assert!(e_str.starts_with("2.71828182845904"), "e = {e_str}");
1581 }
1582
1583 #[test]
1584 fn test_prime_checking() {
1585 let prime = ArbitraryInt::from_i64(97);
1586 assert!(prime.is_probably_prime(20));
1587
1588 let composite = ArbitraryInt::from_i64(98);
1589 assert!(!composite.is_probably_prime(20));
1590 }
1591
1592 #[test]
1593 fn test_gcd_lcm() {
1594 let a = ArbitraryInt::from_i64(48);
1595 let b = ArbitraryInt::from_i64(18);
1596
1597 let gcd = a.gcd(&b);
1598 assert_eq!(gcd.to_string(), "6");
1599
1600 let lcm = a.lcm(&b);
1601 assert_eq!(lcm.to_string(), "144");
1602 }
1603
1604 #[test]
1605 fn test_transcendental_functions() {
1606 let x = ArbitraryFloat::from_f64_withprecision(0.5, 128).expect("Operation failed");
1607
1608 let sin_x = x.sin();
1609 let cos_x = x.cos();
1610 let identity = sin_x.clone() * sin_x + cos_x.clone() * cos_x;
1611
1612 assert!(
1614 (identity.to_f64() - 1.0).abs() < 1e-10,
1615 "identity = {}",
1616 identity.to_f64()
1617 );
1618
1619 let ln_x = x.ln().expect("Operation failed");
1620 let exp_ln_x = ln_x.exp();
1621 assert!(
1622 (exp_ln_x.to_f64() - 0.5).abs() < 1e-10,
1623 "exp_ln = {}",
1624 exp_ln_x.to_f64()
1625 );
1626 }
1627
1628 #[test]
1629 fn testerror_handling() {
1630 let zero = ArbitraryRational::new();
1632 assert!(zero.recip().is_err());
1633
1634 let neg = ArbitraryFloat::from_f64(-1.0);
1636 assert!(neg.sqrt().is_err());
1637
1638 assert!(neg.ln().is_err());
1640
1641 let out_of_range = ArbitraryFloat::from_f64(2.0);
1643 assert!(out_of_range.asin().is_err());
1644 }
1645}