use bigdecimal::{BigDecimal, Zero, One};
use num_bigint::BigInt;
use std::str::FromStr;
use std::fmt::{Display, Formatter, Result as FmtResult};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HighPrecisionDecimal {
value: BigDecimal,
min_precision: usize,
}
impl HighPrecisionDecimal {
pub fn new(value: BigDecimal, min_precision: usize) -> Self {
Self {
value,
min_precision,
}
}
pub fn from_str_with_precision(s: &str, min_precision: usize) -> Result<Self, bigdecimal::ParseBigDecimalError> {
let value = BigDecimal::from_str(s)?;
Ok(Self::new(value, min_precision))
}
pub fn from_bigdecimal(value: BigDecimal) -> Self {
let precision = value.fractional_digit_count().max(0) as usize;
Self::new(value, precision)
}
pub fn tiny(scale: i64) -> Self {
let value = BigDecimal::new(BigInt::from(1), scale);
Self::new(value, scale.max(0) as usize)
}
pub fn value(&self) -> &BigDecimal {
&self.value
}
pub fn min_precision(&self) -> usize {
self.min_precision
}
fn ensure_precision(&self, result: BigDecimal) -> BigDecimal {
let current_precision = result.fractional_digit_count();
if current_precision < self.min_precision as i64 {
result.with_scale(self.min_precision as i64)
} else {
result
}
}
pub fn add(&self, other: &Self) -> Self {
let result_precision = self.min_precision.max(other.min_precision);
let result = &self.value + &other.value;
Self::new(result, result_precision)
}
pub fn sub(&self, other: &Self) -> Self {
let result_precision = self.min_precision.max(other.min_precision);
let result = &self.value - &other.value;
Self::new(result, result_precision)
}
pub fn mul(&self, other: &Self) -> Self {
let result_precision = self.min_precision + other.min_precision;
let result = &self.value * &other.value;
Self::new(result, result_precision)
}
pub fn div(&self, other: &Self) -> Self {
if other.value.is_zero() {
panic!("除零错误");
}
let result_precision = self.min_precision.max(other.min_precision) + 10; let result = &self.value / &other.value;
Self::new(result, result_precision)
}
pub fn is_zero(&self) -> bool {
self.value.is_zero()
}
pub fn is_one(&self) -> bool {
self.value == BigDecimal::one()
}
pub fn to_bigdecimal(&self) -> BigDecimal {
self.value.clone()
}
}
impl Display for HighPrecisionDecimal {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{}", self.value)
}
}
impl From<BigDecimal> for HighPrecisionDecimal {
fn from(value: BigDecimal) -> Self {
Self::from_bigdecimal(value)
}
}
impl From<&str> for HighPrecisionDecimal {
fn from(s: &str) -> Self {
let value = BigDecimal::from_str(s).expect("无效的数值字符串");
Self::from_bigdecimal(value)
}
}
impl From<i32> for HighPrecisionDecimal {
fn from(n: i32) -> Self {
Self::from_bigdecimal(BigDecimal::from(n))
}
}
impl From<f64> for HighPrecisionDecimal {
fn from(f: f64) -> Self {
let value = BigDecimal::try_from(f).expect("无效的浮点数");
Self::from_bigdecimal(value)
}
}
pub mod operations {
use super::*;
pub fn precise_add(a: &BigDecimal, b: &BigDecimal, min_precision: usize) -> BigDecimal {
let result = a + b;
let current_precision = result.fractional_digit_count();
if current_precision < min_precision as i64 {
result.with_scale(min_precision as i64)
} else {
result
}
}
pub fn create_tiny_decimal(scale: i64) -> BigDecimal {
BigDecimal::new(BigInt::from(1), scale)
}
pub fn equals_with_precision(a: &BigDecimal, b: &BigDecimal, precision: usize) -> bool {
let diff = (a - b).abs();
let tolerance = BigDecimal::new(BigInt::from(1), precision as i64 + 1);
diff < tolerance
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_high_precision_creation() {
let tiny = HighPrecisionDecimal::tiny(71);
println!("极小数值: {}", tiny);
assert_eq!(tiny.min_precision(), 71);
}
#[test]
fn test_high_precision_addition() {
let tiny = HighPrecisionDecimal::from_str_with_precision(
"0.00000000000000000000000000000000000000000000000000000000000000000000001",
71
).unwrap();
let point_one = HighPrecisionDecimal::from_str_with_precision("0.1", 1).unwrap();
let result = tiny.add(&point_one);
println!("高精度加法结果: {}", result);
let expected = HighPrecisionDecimal::from_str_with_precision(
"0.10000000000000000000000000000000000000000000000000000000000000000000001",
71
).unwrap();
assert_eq!(result, expected);
}
#[test]
fn test_precision_preservation() {
let a = HighPrecisionDecimal::tiny(50);
let b = HighPrecisionDecimal::from("0.5");
let result = a.add(&b);
println!("精度保持测试: {} + {} = {}", a, b, result);
assert!(result.min_precision() >= 50);
}
#[test]
fn test_operations_module() {
let tiny = operations::create_tiny_decimal(70);
let point_one = BigDecimal::from_str("0.1").unwrap();
let result = operations::precise_add(&tiny, &point_one, 70);
println!("操作模块测试结果: {}", result);
let expected = BigDecimal::from_str("0.1000000000000000000000000000000000000000000000000000000000000000000001").unwrap();
assert!(operations::equals_with_precision(&result, &expected, 70));
}
}