2个版本
0.1.1 | 2024年1月3日 |
---|---|
0.1.0 | 2024年1月3日 |
#615 in 数学
42KB
922 行
astro_float
for nalgebra
此包实现了在astro_float
中的类型
上使用线性代数库BigFloat
nalgebra
所需的特性和功能。此库导出了它自己的类型
,其中BigFloat<CTX>
CTX
是一个计算上下文,用于存储精度和舍入模式。
示例
编译时常量精度
使用已知于编译时的精度和舍入模式与该库一起使用是直接的,可以使用
计算上下文。建议将ConstCtx
BigFloat<ConstCtx<P,RM>>
存储在类型别名中,以便代码更易于阅读。
use astro_nalgebra::{BigFloat, ConstCtx, RoundingMode};
use nalgebra::Vector2;
// This defines a type that has a precision upper bound of
// 1024 bits in the mantissa and no explicit rounding mode
type BF1024 = BigFloat<ConstCtx<1024>>;
// See the documentation on ConstCtx for how to specify a rounding mode
fn main() {
let two: BF1024 = "2".parse().unwrap();
let six: BF1024 = "6".parse().unwrap();
let vec: Vector2<BF1024> = Vector2::new(two,six);
let seven: BF1024 = "7".parse().unwrap();
// Prints [2/7, 6/7] as decimals until 1024 bits
println!("{}", vec / seven);
}
尽管完全可以将类型命名为类似于f1024
,但从技术上讲,这打破了浮点命名方案,因为类型BigFloat<ConstCtx<64>>
的尾数部分有64位,而像f64
这样的类型只有52位尾数,其中有12位保留用于符号和指数。因此,f64
和BigFloat<ConstCtx<64>>
并不相同。
运行时动态精度
动态精度更难实现,因为《nalgebra::RealField》中概述的一些方法没有任何参数,因此精度必须存储在类型中。然而,运行时确定的变量不能存储在const generic中,因此必须有一个具有get_prec
和get_rm
方法的无用类型。有一个宏可以快速定义这个无用类型,它引用一个全局的、线程安全的OnceLock
,该锁在运行时必须设置。
示例
use astro_nalgebra::{BigFloat, make_dyn_ctx, RoundingMode};
// This macro takes in the name of a dynamic context (the new type to be made)
// And the name of a global OnceLock to store the precision and rounding mode.
// The name of this global variable is not important, it just has to be unique
// within the scope of the macro call.
make_dyn_ctx!(DynCtx, DYN_CTX_CELL);
type DynFloat = BigFloat<DynCtx>;
fn main() {
let precision = 88;
let rounding_mode = RoundingMode::None;
// Sets the precision and rounding mode of the DynCtx context.
// This method can only be called once or it will panic.
DynCtx::set(precision, rounding_mode);
let num: DynFloat = "120".parse().unwrap();
}
为什么必须使用泛型来实现
该库可能有两种实现方式
- 一个非常简单的包装器,围绕
astro_float::BigFloat
,将精度存储在结构体本身中。 - 一个包装器,将精度作为泛型存储在类型中。
确保正确精度的唯一方法是使用后一种技术。以下是一个示例,说明前一种技术会如何失败
use nalgebra::RealField;
fn mul_by_pi<T: RealField>(val: T) -> T {
val * T::pi()
}
如果计算所需的精度存储在val中,那么调用BigFloat::pi()
将无法访问精度,因为RealField::pi()
不接受任何参数。因此,所需的精度必须存储在类型本身中。
依赖项
~6MB
~124K SLoC