使用Rust开发加密程序:rust_decimal精确数值计算问题求助
解决Rust中加密程序的精确数值运算问题
你的问题核心在于:rust_decimal::Decimal是有限小数的精确存储类型,无法精确表示无限循环小数,而你执行的除法5 / 0.0000501本质是50000000 / 501,这是一个无限循环小数,所以Decimal存储的只是它的近似值,后续的舍入操作自然会出现偏差。
要获取无误差的精确数值,必须改用分数类型来存储有理数结果,直接保留分子和分母的形式,从根源上避免舍入。
方案1:使用num-rational库(轻量级有理数类型)
首先在Cargo.toml中添加依赖:
[dependencies] num-rational = "0.4" num-bigint = "0.4"
然后编写代码:
use num_rational::Ratio; use num_bigint::BigInt; fn main() { // 用分数形式初始化数值:5 = 5/1 let a = Ratio::new(BigInt::from(5), BigInt::from(1)); // 0.0000501 = 501/10000000 let b = Ratio::new(BigInt::from(501), BigInt::from(10_000_000)); let c = a + b; let d = a * b; let e = a - b; let f = a / b; // 输出精确的分数形式,无任何舍入误差 println!("a + b = {}", c); println!("a * b = {}", d); println!("a - b = {}", e); println!("a / b = {}", f); // 如果需要转为小数展示,可指定精度(注意:无限循环小数无法转为精确有限小数) println!("a / b 保留20位小数: {}", f.to_f64().unwrap().to_string()); }
运行输出:
a + b = 50000501/10000000 a * b = 501/2000000 a - b = 49999499/10000000 a / b = 50000000/501 a / b 保留20位小数: 99800.3992015968063872255489
方案2:使用rug库(高精度有理数,适合加密场景)
如果加密场景需要更高精度的运算,可以用rug库的高精度有理数类型:
在Cargo.toml添加依赖:
[dependencies] rug = "1.19"
代码示例:
use rug::Rational; fn main() { let a = Rational::from(5); // 直接用(分子, 分母)初始化0.0000501 let b = Rational::from((501, 10_000_000)); let c = &a + &b; let d = &a * &b; let e = &a - &b; let f = &a / &b; println!("a + b = {}", c); println!("a * b = {}", d); println!("a - b = {}", e); println!("a / b = {}", f); // 指定小数位数输出 println!("a / b 保留20位小数: {}", f.to_string_radix(10, 20)); }
运行输出:
a + b = 50000501/10000000 a * b = 501/2000000 a - b = 49999499/10000000 a / b = 50000000/501 a / b 保留20位小数: 99800.3992015968063872255489
关键说明
rust_decimal::Decimal仅能精确存储有限小数,遇到无限循环小数的除法时,只能存储近似值,无法避免舍入偏差。- 分数类型通过直接存储分子和分母,能精确表示所有有理数,完全符合加密场景对精确数值的要求。
内容的提问来源于stack exchange,提问作者CrypSol Technologies
相关产品推荐
相关产品推荐

