【学Rust写CAD】15 定点数实现(fixed.rs)

源代码

fixed.rs文件实现了一个定点数(Fixed Point)类型 Fixed,用于在整数运算中模拟小数运算。代码如下:

rust 复制代码
//小数位数
const FIXED_FRACTION_BITS: u32 = 16;
//用于 双线性插值(Bilinear Interpolation) 的计算,它决定了插值权重(weight)的精度位数。一般为4或8
const BILINEAR_INTERPOLATION_BITS: u32 = 4;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Fixed(i32);

impl Fixed {
    pub const ONE: Fixed = Fixed(1 << FIXED_FRACTION_BITS);
    pub const HALF: Fixed = Fixed(1 << (FIXED_FRACTION_BITS-1));//FIXED_ONE
    
    /// 创建新的Fixed值
    pub fn new(value: i32) -> Self {
        Fixed(value)
    }
    
    /// 将浮点数转换为定点数
    pub fn from_float(x: f32) -> Self {
        Fixed(((x * (1 << FIXED_FRACTION_BITS) as f32) + 0.5) as i32)
    }
    
    /// 将定点数转换为整数(截断小数部分)
    pub fn to_int(self) -> i32 {
        self.0 >> FIXED_FRACTION_BITS
    }
    
    /// 获取双线性插值权重
    pub fn bilinear_weight(self) -> u32 {
        // 丢弃不需要的精度位
        let reduced = self.0 >> (FIXED_FRACTION_BITS - BILINEAR_INTERPOLATION_BITS);
        // 提取剩余的小数部分
        let fraction = reduced & ((1 << BILINEAR_INTERPOLATION_BITS) - 1);
        fraction as u32
    }
    
    /// 获取内部值
    pub fn raw_value(self) -> i32 {
        self.0
    }
}

// 实现一些运算符重载以便更方便地使用
impl std::ops::Add for Fixed {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Fixed(self.0 + rhs.0)
    }
}

impl std::ops::Sub for Fixed {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self {
        Fixed(self.0 - rhs.0)
    }
}

impl std::ops::Mul for Fixed {
    type Output = Self;
    fn mul(self, rhs: Self) -> Self {
        // 定点数乘法需要调整小数位
        Fixed((self.0 as i64 * rhs.0 as i64 >> FIXED_FRACTION_BITS) as i32)
    }
}

impl std::ops::Div for Fixed {
    type Output = Self;
    fn div(self, rhs: Self) -> Self {
        // 定点数除法需要调整小数位
        Fixed(((self.0 as i64 << FIXED_FRACTION_BITS) / rhs.0 as i64) as i32)
    }
}

impl std::ops::Shr<u32> for Fixed {
    type Output = Self;
    fn shr(self, rhs: u32) -> Self {
        Fixed(self.0 >> rhs)
    }
}

impl std::ops::Shl<u32> for Fixed {
    type Output = Self;
    fn shl(self, rhs: u32) -> Self {
        Fixed(self.0 << rhs)
    }
}

代码解析:

常量定义
  1. FIXED_FRACTION_BITS: u32 = 16:
  • 表示小数部分占用的位数

  • 使用16位表示小数部分,意味着有16位小数和16位整数(在i32中)

  1. BILINEAR_INTERPOLATION_BITS: u32 = 4:
  • 用于双线性插值计算的精度位数

  • 通常设置为4或8位,决定了插值权重的精度

Fixed 结构体

Fixed 是一个包装了 i32 的新类型,用于表示定点数。

重要常量
  1. ONE: 表示定点数1.0,值为 1 << 16 (65536)

  2. HALF: 表示定点数0.5,值为 1 << 15 (32768)

主要方法
  1. new(value: i32): 直接从一个i32值创建Fixed数

  2. from_float(x: f32): 将浮点数转换为定点数

  • 公式:x * (1 << 16) + 0.5 (0.5用于四舍五入)
  1. to_int(): 将定点数转换为整数(截断小数部分)
  • 右移16位丢弃小数部分
  1. bilinear_weight(): 获取双线性插值权重
  • 先丢弃不需要的精度位(保留BILINEAR_INTERPOLATION_BITS位)

  • 然后提取剩余的小数部分作为权重

  1. raw_value(): 获取内部存储的原始i32值
运算符重载

实现了基本的算术运算,注意乘法和除法的特殊处理:

  1. 乘法:
  • 需要先将操作数扩展为i64防止溢出

  • 结果右移16位调整小数位

  1. 除法:
  • 被除数左移16位扩展

  • 然后进行除法运算

定点数表示原理

这个实现使用Q16.16格式的定点数:

  • 32位整数(i32)中,高16位表示整数部分,低16位表示小数部分

  • 例如:0x00010000 表示1.0 (1 << 16)

  • 例如:0x00008000 表示0.5 (1 << 15)

应用场景

这种定点数实现常用于:

  1. 需要高性能小数运算但不想用浮点数的场合

  2. 图形处理中的坐标计算

  3. 嵌入式系统等不支持浮点运算硬件的环境

  4. 双线性插值等需要精确控制精度的算法

双线性插值中使用时,bilinear_weight()方法提供了权重计算,通过控制BILINEAR_INTERPOLATION_BITS可以调整插值精度。

相关推荐
朝阳5812 小时前
Rust项目GPG签名配置指南
开发语言·后端·rust
朝阳5812 小时前
Rust实现高性能目录扫描工具ll的技术解析
开发语言·后端·rust
红尘散仙6 小时前
六、WebGPU 基础入门——Vertex 缓冲区和 Index 缓冲区
前端·rust·gpu
苏近之6 小时前
深入浅出 Rust 异步运行时原理
rust·源码
红尘散仙7 小时前
四、WebGPU 基础入门——Uniform 缓冲区与内存对齐
前端·rust·gpu
大卫小东(Sheldon)10 小时前
魔方求解器桌面版(层先法,基于Tauri实现)
rust
景天科技苑12 小时前
【Rust结构体】Rust结构体详解:从基础到高级应用
开发语言·后端·rust·结构体·关联函数·rust结构体·结构体方法
苏近之13 小时前
说明白 Rust 中的泛型: 泛型是一种多态
设计模式·rust
bruce5411014 小时前
【智能指针】一文带你入门Rust 智能指针
rust
用户099691880181 天前
Rust JSON 数据处理:take 与 clone 的权衡
rust