为f64类型构建ln值查找表的最优实现方案
方案推荐
1. 标准库无依赖实现(Rust 1.70+ 优先选择)
不用引入任何第三方 crate,直接用标准库的OnceLock加互斥锁实现线程安全的全局可扩容查找表:
use std::sync::{OnceLock, Mutex}; // 全局静态查找表,仅初始化一次 static LNS_LOOKUP: OnceLock<Mutex<Vec<f64>>> = OnceLock::new(); pub fn get_ln(i: u32) -> f64 { // 首次调用时初始化基础表,前两个元素为0.0 let lookup = LNS_LOOKUP.get_or_init(|| { Mutex::new(vec![0.0f64, 0.0f64]) }); let mut table = lookup.lock().unwrap(); let i_usize = i as usize; // 当请求的下标超过当前表长时自动追加计算 if i_usize >= table.len() { for n in table.len()..=i_usize { table.push((n as f64).ln()); } } table[i_usize] }
该实现的优势:
- 无需手动预填常量,所有对数值自动计算
- 仅首次调用初始化基础表,后续相同值直接查表,无重复计算
- 支持动态扩容,遇到更大的i时自动追加新的对数值
- 线程安全,多线程场景下可直接使用
2. 单线程场景优化版
如果你的代码仅在单线程下运行,可以去掉锁开销,用线程本地存储实现,性能更高:
use std::cell::RefCell; thread_local! { static LNS_LOOKUP: RefCell<Vec<f64>> = RefCell::new(vec![0.0f64, 0.0f64]); } pub fn get_ln(i: u32) -> f64 { LNS_LOOKUP.with(|lookup| { let mut table = lookup.borrow_mut(); let i_usize = i as usize; if i_usize >= table.len() { for n in table.len()..=i_usize { table.push((n as f64).ln()); } } table[i_usize] }) }
3. 旧版本Rust兼容方案(需lazy_static依赖)
如果你的Rust版本低于1.70,无法使用标准库的OnceLock,可以用lazy_static crate实现,代码逻辑和标准库版本基本一致:
use lazy_static::lazy_static; use std::sync::Mutex; lazy_static! { static ref LNS_LOOKUP: Mutex<Vec<f64>> = Mutex::new(vec![0.0f64, 0.0f64]); } pub fn get_ln(i: u32) -> f64 { let mut table = LNS_LOOKUP.lock().unwrap(); let i_usize = i as usize; if i_usize >= table.len() { for n in table.len()..=i_usize { table.push((n as f64).ln()); } } table[i_usize] }
内容的提问来源于stack exchange,提问作者C. Bartels
相关产品推荐
相关产品推荐

