Arduino Mega中Rust语言F32浮点数比较异常问题
AVR平台Rust代码中动态计算F32浮点数的比较异常问题
在Arduino Mega上基于Rust开发时,发现一个异常现象:通过加法或类型转换动态生成的F32浮点数,进行比较操作时结果完全错误;但直接使用固定字面量浮点数时,比较结果符合预期。
示例代码
#![no_std] #![no_main] use panic_halt as _; use ufmt_float::uFmt_f32; #[arduino_hal::entry] fn main() -> ! { let dp = arduino_hal::Peripherals::take().unwrap(); let pins = arduino_hal::pins!(dp); let mut serial = arduino_hal::default_serial!(dp, pins, 57600); loop { // let sample_rate = 280.0f32; let mut sample_rate = 100.0f32; for _ in 1..10 { sample_rate = sample_rate + 20.0f32; } let sample_rate_formatted = uFmt_f32::Five(sample_rate); ufmt::uwriteln!(&mut serial, "Sample rate: {}", sample_rate_formatted).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.to_bits() : {}",sample_rate.to_bits()).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.is_sign_negative() : {}",sample_rate.is_sign_negative()).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.is_sign_positive() : {}",sample_rate.is_sign_positive()).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.is_nan() : {}",sample_rate.is_nan()).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.is_finite() : {}",sample_rate.is_finite()).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.is_infinite() : {}",sample_rate.is_infinite()).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.is_normal() : {}",sample_rate.is_normal()).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.is_subnormal() : {}",sample_rate.is_subnormal()).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.lt(0.0) : {}", sample_rate.lt(&0.0)).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.gt(0.0) : {}", sample_rate.gt(&0.0)).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.eq(0.0) : {}", sample_rate.eq(&0.0)).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.lt(0.1) : {}", sample_rate.lt(&0.1)).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.gt(0.1) : {}", sample_rate.gt(&0.1)).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.eq(0.1) : {}", sample_rate.eq(&0.1)).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.lt(-0.1) : {}", sample_rate.lt(&-0.1)).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.gt(-0.1) : {}", sample_rate.gt(&-0.1)).unwrap(); ufmt::uwriteln!(&mut serial, "sample_rate.eq(-0.1) : {}", sample_rate.eq(&-0.1)).unwrap(); loop { } } }
动态计算时的错误输出
Sample rate: 280.00000 sample_rate.to_bits() : 1133248512 sample_rate.is_sign_negative() : false sample_rate.is_sign_positive() : true sample_rate.is_nan() : false sample_rate.is_finite() : true sample_rate.is_infinite() : true sample_rate.is_normal() : false sample_rate.is_subnormal() : false sample_rate.lt(0.0) : false sample_rate.gt(0.0) : false sample_rate.eq(0.0) : true sample_rate.lt(0.1) : false sample_rate.gt(0.1) : false sample_rate.eq(0.1) : true sample_rate.lt(-0.1) : false sample_rate.gt(-0.1) : false sample_rate.eq(-0.1) : true
使用字面量时的正确输出
取消注释代码中的let sample_rate = 280.0f32;并注释动态计算部分后,得到正常输出:
Sample rate: 280.00000 sample_rate.to_bits() : 1133248512 sample_rate.is_sign_negative() : false sample_rate.is_sign_positive() : true sample_rate.is_nan() : false sample_rate.is_finite() : true sample_rate.is_infinite() : false sample_rate.is_normal() : false sample_rate.is_subnormal() : false sample_rate.lt(0.0) : false sample_rate.gt(0.0) : true sample_rate.eq(0.0) : false sample_rate.lt(0.1) : false sample_rate.gt(0.1) : true sample_rate.eq(0.1) : false sample_rate.lt(-0.1) : false sample_rate.gt(-0.1) : true sample_rate.eq(-0.1) : false
已尝试的解决方法
- 截取浮点数的截断值
- 将系统默认的avr-gcc 5.4.0升级为avr-gcc-12
项目Cargo.toml配置
[package] name = "f32demo" version = "0.1.0" authors = ["thefoxrhythm"] edition = "2021" license = "MIT OR Apache-2.0" [[bin]] name = "f32demo" test = false bench = false [dependencies] panic-halt = "0.2.0" ufmt = "0.2.0" nb = "0.1.2" embedded-hal = "0.2.3" ufmt_float ="0.2.0" [dependencies.avr-device] version = "0.5.0" features = ["atmega2560"] [dependencies.arduino-hal] git = "https://github.com/rahix/avr-hal" rev = "4c9c44c314eb061ee20556ef10d45dea36e75ee4" features = ["arduino-mega2560"] # Configure the build for minimal size - AVRs have very little program memory [profile.dev] panic = "abort" lto = true opt-level = "s" [profile.release] panic = "abort" codegen-units = 1 debug = true lto = true strip = true opt-level = 1
内容的提问来源于stack exchange,提问作者Melody Fox
相关产品推荐
相关产品推荐

