Rust中检查阿姆斯特朗数遇整数溢出panic,该如何处理?
处理阿姆斯特朗数检查中的整数溢出问题
你在Exercism上的阿姆斯特朗数检查代码触发了整数溢出panic,错误信息如下:
thread 'properly_handles_overflow' panicked at 'attempt to add with overflow', src/lib.rs:9:9
原代码:
use std::io; pub fn is_armstrong_number(mut num: u32) -> bool { let check = num; let mut sum = 0; let length = (num as f64).log(10.0).floor() as u32 + 1; while num != 0 { let digit = num % 10; sum += u32::pow(digit, length); num = num / 10; } if sum == check { return true; } else { return false; } } fn main() { let mut input = String::new(); io::stdin().read_line(&mut input); let number: u32 = input.trim().parse().unwrap(); is_armstrong_number(number); }
问题原因
Rust默认在debug模式下会检查整数运算溢出并触发panic。原代码中,当计算u32::pow(digit, length)时,若结果超出u32的最大值(4294967295),或者累加后sum超出u32范围,就会触发溢出错误。
解决方案
1. 使用更宽的整数类型存储总和
将sum的类型改为u64,利用其更大的存储空间避免溢出,最后再与原数比较:
pub fn is_armstrong_number(mut num: u32) -> bool { let check = num; let mut sum: u64 = 0; let length = (num as f64).log(10.0).floor() as u32 + 1; while num != 0 { let digit = num % 10; sum += u64::from(u32::pow(digit, length)); num = num / 10; } sum == u64::from(check) }
2. 使用溢出安全的方法检查运算
Rust提供了checked_pow和checked_add方法,它们在溢出时返回None,可直接以此判定结果:
pub fn is_armstrong_number(mut num: u32) -> bool { let check = num; let mut sum = 0; let length = (num as f64).log(10.0).floor() as u32 + 1; while num != 0 { let digit = num % 10; // 幂运算溢出则直接返回false let pow_result = match digit.checked_pow(length) { Some(p) => p, None => return false, }; // 累加溢出也返回false sum = match sum.checked_add(pow_result) { Some(s) => s, None => return false, }; num = num / 10; } sum == check }
3. 优化位数计算+溢出安全处理
原代码用浮点log(10)计算位数可能存在精度误差,改用循环计算位数,同时结合溢出检查:
pub fn is_armstrong_number(mut num: u32) -> bool { let check = num; let mut temp = num; let mut length = 0; // 循环计算位数,避免浮点精度问题 while temp != 0 { length += 1; temp /= 10; } // 处理0的特殊情况 if length == 0 { return true; } let mut sum = 0; temp = num; while temp != 0 { let digit = temp % 10; match digit.checked_pow(length) { None => return false, Some(p) => { sum = match sum.checked_add(p) { Some(s) => s, None => return false, }; } } temp /= 10; } sum == check }
内容的提问来源于stack exchange,提问作者user14473720
相关产品推荐
相关产品推荐

