为什么浮点数计算结果不一致?(指的是帧同步里,两个客户端计算结果可能不一致)
因为整数是有限的,小数是无限的,每一位精度都表示不同的小数
比如某个无限不循环小数,0.1524512345454564…
那么计算机如何表示这样的小数呢?
通过 IEEE二进制浮点数算术标准,在不同的CPU可能标准不一致,所以会导致计算结果不一致
也可以理解为:某个计算机存储的是0.15245 另一个存的是0.1524512345
这样计算出来的结果肯定有误差了
什么是定点数?
就是小数点的位置不变,比如:永远表示小数点后四位小数
这样计算的结果就会一致了
如何表示定点数?
一般都是通过整数类型表示的,比如:
int类型,有32位,前15位表示整数,后面16位表示小数,可以表示为15.16的小数
long类型,有64位,前31位表示整数,后面32位表示小数,可以表示为31.32的小数
具体如何选择,就要看自己项目内的精确程度,以及空间占用等问题考虑
正题开始!!
本文介绍的是一种简单的定点数实现方式,就是对某个值✖10000的方式
这样可以表示四位小数(四位小数一般情况下够用,除非有三角函数or开方等复杂计算)
说明:
一个float类型的数【1.327545】转化位一个int类型的数存储【13275】
(后面的【0.000045】就会舍弃,导致精度丢失计算结果有误差)
一个int类型的数【15】转化成一个int类型的数存储【150000】
(其实也可以不转化,计算时需要判断下如果小于10000就知道是小数,大于10000就知道是整数,这里只是为了方便看懂,统一计算规则)
构造代码展示:
public partial struct FP
{
//基准倍数
public const int CARDINAL_NUMBER = 10000;
//内部真实存的值
public int rawValue;
/// <summary>
/// 构造一个定点数
/// 重载一个带bool值的就是区分是否直接直接设置RawValue
/// </summary>
/// <param name="value">真实的数</param>
/// <param name="rawSet">无用参数,占位</param>
public FP(int value, bool rawSet)
{
rawValue = value;
}
/// <summary>
/// 构造一个定点数,内部会✖️10000存储
/// </summary>
/// <param name="value">真实的数</param>
public FP(int value)
{
rawValue = value * CARDINAL_NUMBER;
}
/// <summary>
/// 构造一个定点数,内部会✖️10000存储
/// 会舍弃Float的四位小数后面的小数位
/// 关于精度问题,可以简单再加一个变量记录位移了几位解决,或者使用其他的表示方式
/// </summary>
/// <param name="value">真实的数</param>
public FP(float value)
{
rawValue = (int) (value * CARDINAL_NUMBER);
}
}
这样构造一个FP(定点数)的核心代码就完成了
但是这样用起来就会十分不方便,比如 加减乘除 运算都没有重写操作符
所以下一步就是进一步拓展它内部的运算法则:
1.显示/隐式转换
2.重载±*/操作符
3.数学函数相关计算(绝对值,开方,三角函数等)