本文已参与「新人创作礼」活动,一起开启掘金创作之路。
帧同步之:定点数原理、运算、实现
简述
- 定点数:小数点固定的数
- 浮点数:小数点不固定的数
一些背景知识
- 本文假设你拥有计算机组成原理中有关二进制、操作符、位运算的相关知识
// 左移操作时将运算数的二进制码整体左移指定位数,左移之后的空位用0补充
// 右移操作是将运算数的二进制码整体右移指定位数,右移之后的空位用符号位补充,如果是正数用0补充,负数用1补充
// 负数,计算机中使用补码的方式表示
// 补码 = ~原码 + 1
// -1的码:~(10000000 00000000 00000000 00000001) + 1 => 01111111 11111111 11111111 11111110 + 1
定点数和浮点数比较
- 性能:定点数 > 浮点数,根据我的测试结果,c#中4到5倍的性能差距
- 范围:定点数 < 浮点数,根据需要控制小数位,比如我使用16位小数位,有一位符号位,那么范围是(负2的47次方, 正2的47次方-1)
- 一致性:定点数不同平台运算结果一致,浮点数不同平台运算结果可能不同
定点数表示
- 根据需要使用32位或者64位整形表示
定点数原理
- 使用整形数中的一部分bit位作为整数部分,剩下的作为小数部分
实现
class FixVal{
const int total_bit_cnt = 64;
const int f_bit_cnt = 16;
const int i_bit_cnt = total_bit_cnt - f_bit_cnt;
const long f_mask = (long)(ulong.MaxValue >> i_bit_cnt);
const long i_mask = (long)(-1L & ~f_mask);
const long f_range = f_mask + 1;
public const long min_val = long.MinValue >> f_bit_cnt;
public const long max_val = long.MaxValue >> f_bit_cnt;
long mRaw;
public FixVal(int intVal):this(((long)intVal) << f_bit_cnt){
}
public FixVal(long raw){
mRaw = raw;
}
public long GetRaw(){
return mRaw;
}
public static FixVal operator +(FixVal a, FixVal b){
return new FixVal(a.mRaw + b.mRaw);
}
public static FixVal operator -(FixVal a, FixVal b){
return new FixVal(a.mRaw - b.mRaw);
}
public static FixVal operator *(FixVal a, FixVal b){
return new FixVal((a.mRaw * b.mRaw + (f_range >> 1)) >> f_bit_cnt);
}
public static FixVal operator /(FixVal a, FixVal b){
return new FixVal((a.mRaw << f_bit_cnt) / b.mRaw);
}
public static explicit operator double (FixVal fixVal){
return (double)(fixVal.mRaw >> f_bit_cnt) + (fixVal.mRaw & f_mask) / (double)f_range;
}
}
测试结果
- 测试代码
FixVal a = new FixVal(35532);
FixVal b = new FixVal(5);
FixVal c = a / b;
Console.WriteLine(c.GetRaw());
double d = (double)c;
Console.WriteLine(d);
Console.WriteLine(35532f / 5f);
- 输出
465725030
7106.39999389648
7106.4
小结
- 定点数提供了一种高性能的可用于帧同步中保障多平台计算结果一致性的方案