首页 > 解决方案 > 如何从具有整数和分数的任意拆分的原始整数类型解析二进制补码定点数?

问题描述

我正在解析 OpenType 字体文件,需要解析(和写入)两种定点数:

我认为,最后,它应该被投向/从f32


OpenType 规范描述:

F2DOT14 格式由一个带符号的 2 的补码整数和一个无符号小数组成。要计算实际值,请取整数并加上分数。

2.14 值的示例是:

Decimal Value   Hex Value   Integer     Fraction
1.999939        0x7fff      1           16383/16384
1.75            0x7000      1           12288/16384
0.000061        0x0001      0           1/16384
0.0             0x0000      0           0/16384
-0.000061       0xffff      -1          16383/16384
-2.0            0x8000      -2          0/16384

我有一个有效的解决方案,但仅适用于 2.14 值:

fn from(number: u16) -> f32 {
    let mut int = (number >> 14) as f32;
    if int > 1f32 {
        int -= 4f32;
    }
    let frac = (number & 0b11_1111_1111_1111) as f32 / 16384 as f32;
    int + frac
}

因为整数值应该是[-2, 2),所以如果解析出的整数大于1,我就减4,得到负数。

我正在寻找一种方法来在Rust 整数原始类型( 、、等)的标准范围内对定点数(如2.1416.163.5、等)进行任何可能的拆分。24.40u16u32u64

标签: rusttype-conversionfixed-point

解决方案


能够解决我的问题,这是解析 16 位定点数的示例:

use std::mem::size_of;

fn from_u16(raw: u16, frac_count: usize) -> f32 {
  let bit_count = size_of::<u16>() * 8;
  let int_count = bit_count - frac_count;

  let unsigned = (raw >> frac_count) as isize;
  let sign_bit = unsigned >> (int_count - 1) & 1;
  let high_bits = if sign_bit == 1 { -1 } else { 0 };
  let signed = high_bits << int_count | unsigned as isize;

  let mut mask = 0;
  for i in 0..=frac_count {
    mask = mask << i | 1;
  }

  let frac = (raw & mask) as f32 / (1 << frac_count) as f32;
  signed as f32 + frac
}

推荐阅读