介绍
众所周知定点数是用于做帧同步时保持不同cpu不同设备保持一致稳定的代替浮点数的变量,这里提供了之前封装好的定点数、定点数二维向量、定点数三位向量、定点数数学类。这里不是物理库,知识定点数变量。
定点数类库
浮点数
浮点数也就是float占用4个字节,而定点数是8long类型占用8个字节。不同的cpu机器在计算浮点数的时候都会有微小的差错,比如unity面板中设置一个对象的位置Position,有时候你输入的是一个整数,后来变成了接近你这个整数的.99或者.998等(用Unity时间久的应该是能感受到)。这是因为你输入之后cpu是要经过计算显示出来的。那么这种情况下我们在做帧同步的时候每个机型不一样,计算出来的float也会有差别,帧同步中有微乎其微的差别计算到最后也会是巨大的差别,会影响整个比赛的结果。
定点数
定点数通常使用long类型来计算,这里说明一下为什么是long类型,比如说一个浮点数9.988879,那么定点数可以这样标识,前4个字节记录9988879、后4个字节记录小数点(.)在第几位,最后拼接成我们想要的结果,这样就能保证不同的机器中运算结果一致。
封装的定点数FixedNumber
具体的使用方式其实跟Int float差不太多,只是API可能略有不同,下面是定点数完整的代码,具体的用法我就不做详细说明了,我简单的说明一下
用法
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
FixedNumber fn = new FixedNumber(f);
Debug.LogError(fn);
Debug.LogError(fn.GetValue());
Debug.LogError(fn.ToFloat());
}
}
定点数代码文章来源:https://www.toymoban.com/news/detail-828772.html
using System;
/// <summary>
/// 定点数 使用Int64实现
/// </summary>
[Serializable]
public struct FixedNumber
{
/// <summary>
/// 小数占用位数
/// </summary>
public static int Fix_Fracbits = 16;
/// <summary>
/// 0
/// </summary>
public static FixedNumber Zero = new FixedNumber(0);
internal Int64 m_Bits;
public FixedNumber(int x)
{
m_Bits = (x << Fix_Fracbits);
}
public FixedNumber(float x)
{
m_Bits = (Int64)((x) * (1 << Fix_Fracbits));
}
public FixedNumber(Int64 x)
{
m_Bits = ((x) * (1 << Fix_Fracbits));
}
public Int64 GetValue()
{
return m_Bits;
}
public FixedNumber SetValue(Int64 i)
{
m_Bits = i;
return this;
}
public static FixedNumber Lerp(FixedNumber a, FixedNumber b, float t)
{
return a + (b - a) * t;
}
public static FixedNumber Lerp(FixedNumber a, FixedNumber b, FixedNumber t)
{
return a + (b - a) * t;
}
public FixedNumber Abs()
{
return FixedNumber.Abs(this);
}
public FixedNumber Sqrt()
{
return FixedNumber.Sqrt(this);
}
//******************* + **************************
public static FixedNumber operator +(FixedNumber p1, FixedNumber p2)
{
FixedNumber tmp;
tmp.m_Bits = p1.m_Bits + p2.m_Bits;
return tmp;
}
public static FixedNumber operator +(FixedNumber p1, int p2)
{
FixedNumber tmp;
tmp.m_Bits = p1.m_Bits + (Int64)(p2 << Fix_Fracbits);
return tmp;
}
public static FixedNumber operator +(int p1, FixedNumber p2)
{
return p2 + p1;
}
public static FixedNumber operator +(FixedNumber p1, Int64 p2)
{
FixedNumber tmp;
tmp.m_Bits = p1.m_Bits + p2 << Fix_Fracbits;
return tmp;
}
public static FixedNumber operator +(Int64 p1, FixedNumber p2)
{
return p2 + p1;
}
public static FixedNumber operator +(FixedNumber p1, float p2)
{
FixedNumber tmp;
tmp.m_Bits = p1.m_Bits + (Int64)(p2 * (1 << Fix_Fracbits));
return tmp;
}
public static FixedNumber operator +(float p1, FixedNumber p2)
{
FixedNumber tmp = p2 + p1;
return tmp;
}
//******************* - **************************
public static FixedNumber operator -(FixedNumber p1, FixedNumber p2)
{
FixedNumber tmp;
tmp.m_Bits = p1.m_Bits - p2.m_Bits;
return tmp;
}
public static FixedNumber operator -(FixedNumber p1, int p2)
{
FixedNumber tmp;
tmp.m_Bits = p1.m_Bits - (Int64)(p2 << Fix_Fracbits);
return tmp;
}
public static FixedNumber operator -(int p1, FixedNumber p2)
{
FixedNumber tmp;
tmp.m_Bits = (p1 << Fix_Fracbits) - p2.m_Bits;
return tmp;
}
public static FixedNumber operator -(FixedNumber p1, Int64 p2)
{
FixedNumber tmp;
tmp.m_Bits = p1.m_Bits - (p2 << Fix_Fracbits);
return tmp;
}
public static FixedNumber operator -(Int64 p1, FixedNumber p2)
{
FixedNumber tmp;
tmp.m_Bits = (p1 << Fix_Fracbits) - p2.m_Bits;
return tmp;
}
public static FixedNumber operator -(float p1, FixedNumber p2)
{
FixedNumber tmp;
tmp.m_Bits = (Int64)(p1 * (1 << Fix_Fracbits)) - p2.m_Bits;
return tmp;
}
public static FixedNumber operator -(FixedNumber p1, float p2)
{
FixedNumber tmp;
tmp.m_Bits = p1.m_Bits - (Int64)(p2 * (1 << Fix_Fracbits));
return tmp;
}
//******************* * **************************
public static FixedNumber operator *(FixedNumber p1, FixedNumber p2)
{
FixedNumber tmp;
tmp.m_Bits = ((p1.m_Bits) * (p2.m_Bits)) >> (Fix_Fracbits);
return tmp;
}
public static FixedNumber operator *(int p1, FixedNumber p2)
{
FixedNumber tmp;
tmp.m_Bits = p1 * p2.m_Bits;
return tmp;
}
public static FixedNumber operator *(FixedNumber p1, int p2)
{
return p2 * p1;
}
public static FixedNumber operator *(FixedNumber p1, float p2)
{
FixedNumber tmp;
tmp.m_Bits = (Int64)(p1.m_Bits * p2);
return tmp;
}
public static FixedNumber operator *(float p1, FixedNumber p2)
{
FixedNumber tmp;
tmp.m_Bits = (Int64)(p1 * p2.m_Bits);
return tmp;
}
//******************* / **************************
public static FixedNumber operator /(FixedNumber p1, FixedNumber p2)
{
FixedNumber tmp;
if (p2 == FixedNumber.Zero)
{
//UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
tmp.m_Bits = (p1.m_Bits) * (1 << Fix_Fracbits) / (p2.m_Bits);
}
return tmp;
}
public static FixedNumber operator /(FixedNumber p1, int p2)
{
FixedNumber tmp;
if (p2 == 0)
{
//UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
tmp.m_Bits = p1.m_Bits / (p2);
}
return tmp;
}
public static FixedNumber operator %(FixedNumber p1, int p2)
{
FixedNumber tmp;
if (p2 == 0)
{
//UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
tmp.m_Bits = (p1.m_Bits % (p2 << Fix_Fracbits));
}
return tmp;
}
public static FixedNumber operator /(int p1, FixedNumber p2)
{
FixedNumber tmp;
if (p2 == Zero)
{
//UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
Int64 tmp2 = ((Int64)p1 << Fix_Fracbits << Fix_Fracbits);
tmp.m_Bits = tmp2 / (p2.m_Bits);
}
return tmp;
}
public static FixedNumber operator /(FixedNumber p1, Int64 p2)
{
FixedNumber tmp;
if (p2 == 0)
{
//UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
tmp.m_Bits = p1.m_Bits / (p2);
}
return tmp;
}
public static FixedNumber operator /(Int64 p1, FixedNumber p2)
{
FixedNumber tmp;
if (p2 == Zero)
{
//UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
if (p1 > Int32.MaxValue || p1 < Int32.MinValue)
{
tmp.m_Bits = 0;
return tmp;
}
tmp.m_Bits = (p1 << Fix_Fracbits) / (p2.m_Bits);
}
return tmp;
}
public static FixedNumber operator /(float p1, FixedNumber p2)
{
FixedNumber tmp;
if (p2 == Zero)
{
//UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
Int64 tmp1 = (Int64)p1 * ((Int64)1 << Fix_Fracbits << Fix_Fracbits);
tmp.m_Bits = (tmp1) / (p2.m_Bits);
}
return tmp;
}
public static FixedNumber operator /(FixedNumber p1, float p2)
{
FixedNumber tmp;
if (p2 > -0.000001f && p2 < 0.000001f)
{
//UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
tmp.m_Bits = (p1.m_Bits << Fix_Fracbits) / ((Int64)(p2 * (1 << Fix_Fracbits)));
}
return tmp;
}
public static FixedNumber Sqrt(FixedNumber p1)
{
FixedNumber tmp;
Int64 ltmp = p1.m_Bits * (1 << Fix_Fracbits);
tmp.m_Bits = (Int64)Math.Sqrt(ltmp);
return tmp;
}
public static bool operator >(FixedNumber p1, FixedNumber p2)
{
return (p1.m_Bits > p2.m_Bits) ? true : false;
}
public static bool operator <(FixedNumber p1, FixedNumber p2)
{
return (p1.m_Bits < p2.m_Bits) ? true : false;
}
public static bool operator <=(FixedNumber p1, FixedNumber p2)
{
return (p1.m_Bits <= p2.m_Bits) ? true : false;
}
public static bool operator >=(FixedNumber p1, FixedNumber p2)
{
return (p1.m_Bits >= p2.m_Bits) ? true : false;
}
public static bool operator !=(FixedNumber p1, FixedNumber p2)
{
return (p1.m_Bits != p2.m_Bits) ? true : false;
}
public static bool operator ==(FixedNumber p1, FixedNumber p2)
{
return (p1.m_Bits == p2.m_Bits) ? true : false;
}
public static bool Equals(FixedNumber p1, FixedNumber p2)
{
return (p1.m_Bits == p2.m_Bits) ? true : false;
}
public bool Equals(FixedNumber right)
{
if (m_Bits == right.m_Bits)
{
return true;
}
return false;
}
public static bool operator >(FixedNumber p1, float p2)
{
return (p1.m_Bits > (p2 * (1 << Fix_Fracbits))) ? true : false;
}
public static bool operator <(FixedNumber p1, float p2)
{
return (p1.m_Bits < (p2 * (1 << Fix_Fracbits))) ? true : false;
}
public static bool operator <=(FixedNumber p1, float p2)
{
return (p1.m_Bits <= p2 * (1 << Fix_Fracbits)) ? true : false;
}
public static bool operator >=(FixedNumber p1, float p2)
{
return (p1.m_Bits >= p2 * (1 << Fix_Fracbits)) ? true : false;
}
public static bool operator !=(FixedNumber p1, float p2)
{
return (p1.m_Bits != p2 * (1 << Fix_Fracbits)) ? true : false;
}
public static bool operator ==(FixedNumber p1, float p2)
{
return (p1.m_Bits == p2 * (1 << Fix_Fracbits)) ? true : false;
}
public static FixedNumber Max()
{
FixedNumber tmp;
tmp.m_Bits = Int64.MaxValue;
return tmp;
}
public static FixedNumber Max(FixedNumber p1, FixedNumber p2)
{
return p1.m_Bits > p2.m_Bits ? p1 : p2;
}
public static FixedNumber Min(FixedNumber p1, FixedNumber p2)
{
return p1.m_Bits < p2.m_Bits ? p1 : p2;
}
public static FixedNumber Precision()
{
FixedNumber tmp;
tmp.m_Bits = 1;
return tmp;
}
public static FixedNumber MaxValue()
{
FixedNumber tmp;
tmp.m_Bits = Int64.MaxValue;
return tmp;
}
public static FixedNumber Abs(FixedNumber P1)
{
FixedNumber tmp;
tmp.m_Bits = Math.Abs(P1.m_Bits);
return tmp;
}
public static FixedNumber operator -(FixedNumber p1)
{
FixedNumber tmp;
tmp.m_Bits = -p1.m_Bits;
return tmp;
}
public float ToFloat()
{
return m_Bits / (float)(1 << Fix_Fracbits);
}
public UnityEngine.Quaternion ToUnityRotation()
{
return UnityEngine.Quaternion.Euler(0, -this.ToFloat(), 0);
}
public int ToInt()
{
return (int)(m_Bits >> (Fix_Fracbits));
}
public override string ToString()
{
double tmp = (double)m_Bits / (double)(1 << Fix_Fracbits);
return tmp.ToString();
}
}
定点数二维向量
using UnityEngine;
/// <summary>
/// 定点数二维向量
/// </summary>
[System.Serializable]
public struct Fixed2
{
public FixedNumber x;
public FixedNumber y;
public Fixed2(float x, float y)
{
this.x = new FixedNumber(x);
this.y = new FixedNumber(y);
}
public Fixed2(FixedNumber x, FixedNumber y)
{
this.x = x;
this.y = y;
}
public Vector3 ToVector3()
{
return new Vector3(x.ToFloat(), 0, y.ToFloat());
}
public static Fixed2 GetV2(FixedNumber x, FixedNumber y)
{
return new Fixed2(x, y);
}
public static Fixed2 operator +(Fixed2 a, Fixed2 b)
{
return new Fixed2(a.x + b.x, a.y + b.y);
}
public static Fixed2 operator -(Fixed2 a, Fixed2 b)
{
return new Fixed2(a.x - b.x, a.y - b.y);
}
public static Fixed2 operator *(Fixed2 a, FixedNumber b)
{
return new Fixed2(a.x * b, a.y * b);
}
public Fixed2 Rotate(FixedNumber value)
{
FixedNumber tx, ty;
tx = MathFixed.CosAngle(value) * x - y * MathFixed.SinAngle(value);
ty = MathFixed.CosAngle(value) * y + x * MathFixed.SinAngle(value);
//1,0 tx=1*0-0 ty
return new Fixed2(tx, ty);
}
public FixedNumber ToRotation()
{
if (x == 0 && y == 0)
{
return new FixedNumber();
}
FixedNumber sin = this.normalized.y;
if (this.x >= 0)
{
return MathFixed.Asin(sin) / MathFixed.PI * 180;
}
else
{
return MathFixed.Asin(-sin) / MathFixed.PI * 180 + 180;
}
}
public static Fixed2 Parse(FixedNumber ratio)
{
return new Fixed2(MathFixed.CosAngle(ratio), MathFixed.SinAngle(ratio));
}
public Fixed2 normalized
{
get
{
if (x == 0 && y == 0)
{
return new Fixed2();
}
FixedNumber n = ((x * x) + (y * y)).Sqrt();
return new Fixed2(x / n, y / n);
}
}
public static Fixed2 left = new Fixed2(-1, 0);
public static Fixed2 right = new Fixed2(1, 0);
public static Fixed2 up = new Fixed2(0, 1);
public static Fixed2 down = new Fixed2(0, -1);
public static Fixed2 zero = new Fixed2(0, 0);
public FixedNumber Dot(Fixed2 b)
{
return Dot(this, b);
}
public static FixedNumber Dot(Fixed2 a, Fixed2 b)
{
return a.x * b.x + b.y * a.y;
}
public static Fixed2 operator -(Fixed2 a)
{
return new Fixed2(-a.x, -a.y);
}
public static Fixed3 operator *(Fixed2 a, Fixed2 b)
{
return new Fixed3(new FixedNumber(), new FixedNumber(), a.x * b.y - a.y * b.x);
}
public static bool operator ==(Fixed2 a, Fixed2 b)
{
return a.x == b.x && a.y == b.y;
}
public static bool operator !=(Fixed2 a, Fixed2 b)
{
return a.x != b.x || a.y != b.y;
}
public override string ToString()
{
return "{" + x.ToString() + "," + y.ToString() + "}";
}
}
定点数三维向量
using UnityEngine;
/// <summary>
/// 定点数三维向量
/// </summary>
public struct Fixed3
{
public FixedNumber x
{
get;
private set;
}
public FixedNumber y
{
get;
private set;
}
public FixedNumber z
{
get;
private set;
}
public Fixed3(int x = 0, int y = 0, int z = 0)
{
this.x = new FixedNumber(x);
this.y = new FixedNumber(y);
this.z = new FixedNumber(z);
}
public Fixed3(float x, float y, float z)
{
this.x = new FixedNumber(x);
this.y = new FixedNumber(y);
this.z = new FixedNumber(z);
}
public Fixed3(FixedNumber x, FixedNumber y, FixedNumber z)
{
this.x = x;
this.y = y;
this.z = z;
}
public Vector3 ToVector3()
{
return new Vector3(x.ToFloat(), 0, y.ToFloat());
}
public static Fixed3 operator +(Fixed3 a, Fixed3 b)
{
return new Fixed3(a.x + b.x, a.y + b.y, a.z + b.z);
}
public static Fixed3 operator -(Fixed3 a, Fixed3 b)
{
return new Fixed3(a.x - b.x, a.y - b.y, a.z - b.z);
}
public static Fixed3 left = new Fixed3(-1, 0);
public static Fixed3 right = new Fixed3(1, 0);
public static Fixed3 up = new Fixed3(0, 1);
public static Fixed3 down = new Fixed3(0, -1);
public static Fixed3 zero = new Fixed3(0, 0);
public FixedNumber Dot(Fixed3 b)
{
return Dot(this, b);
}
public static FixedNumber Dot(Fixed3 a, Fixed3 b)
{
return a.x * b.x + b.y * a.y;
}
public static Fixed3 operator -(Fixed3 a)
{
return new Fixed3(-a.x, -a.y, -a.z);
}
public static Fixed2 operator *(Fixed3 a, Fixed2 b)
{
return new Fixed2(-a.z * b.y, a.z * b.x);
}
public override string ToString()
{
return "{" + x.ToString() + "," + y.ToString() + "}";
}
}
定点数数学类
using System.Collections.Generic;
/// <summary>
/// 定点数数学类
/// </summary>
class MathFixed
{
protected static int tabCount = 18 * 4;
/// <summary>
/// sin值对应表
/// </summary>
protected static readonly List<FixedNumber> _m_SinTab = new List<FixedNumber>();
public static readonly FixedNumber PI = new FixedNumber(3.14159265f);
protected static FixedNumber GetSinTab(FixedNumber r)
{
FixedNumber i = new FixedNumber(r.ToInt());
//UnityEngine.Debug.Log(i.ToInt());
if (i.ToInt() == _m_SinTab.Count - 1)
{
return _m_SinTab[(int)i.ToInt()];
}
else
{
// UnityEngine.Debug.Log(i.ToInt()+":"+ _m_SinTab[i.ToInt()]+":"+ Ratio.Lerp(_m_SinTab[i.ToInt()], _m_SinTab[(i + 1).ToInt()], r - i));
return FixedNumber.Lerp(_m_SinTab[(int)i.ToInt()], _m_SinTab[(int)(i + 1).ToInt()], r - i);
}
}
public static FixedNumber GetAsinTab(FixedNumber sin)
{
MathFixed math = Instance;
//UnityEngine.Debug.Log("GetAsinTab");
for (int i = _m_SinTab.Count - 1; i >= 0; i--)
{
if (sin > _m_SinTab[i])
{
if (i == _m_SinTab.Count - 1)
{
return new FixedNumber(i) / (tabCount / 4) * (PI / 2);
}
else
{
//return new Ratio(i);
return FixedNumber.Lerp(new FixedNumber(i), new FixedNumber(i + 1), (sin - _m_SinTab[i]) / (_m_SinTab[i + 1] - _m_SinTab[i])) / (tabCount / 4) * (PI / 2);
}
}
}
return new FixedNumber();
}
protected static MathFixed Instance
{
get
{
if (_m_instance == null)
{
_m_instance = new MathFixed();
}
return _m_instance;
}
}
protected static MathFixed _m_instance;
protected MathFixed()
{
if (_m_instance == null)
{
_m_SinTab.Add(new FixedNumber(0f));//0
_m_SinTab.Add(new FixedNumber(0.08715f));
_m_SinTab.Add(new FixedNumber(0.17364f));
_m_SinTab.Add(new FixedNumber(0.25881f));
_m_SinTab.Add(new FixedNumber(0.34202f));//20
_m_SinTab.Add(new FixedNumber(0.42261f));
_m_SinTab.Add(new FixedNumber(0.5f));
_m_SinTab.Add(new FixedNumber(0.57357f));//35
_m_SinTab.Add(new FixedNumber(0.64278f));
_m_SinTab.Add(new FixedNumber(0.70710f));
_m_SinTab.Add(new FixedNumber(0.76604f));
_m_SinTab.Add(new FixedNumber(0.81915f));//55
_m_SinTab.Add(new FixedNumber(0.86602f));//60
_m_SinTab.Add(new FixedNumber(0.90630f));
_m_SinTab.Add(new FixedNumber(0.93969f));
_m_SinTab.Add(new FixedNumber(0.96592f));
_m_SinTab.Add(new FixedNumber(0.98480f));//80
_m_SinTab.Add(new FixedNumber(0.99619f));
_m_SinTab.Add(new FixedNumber(1f));
}
}
public static FixedNumber PiToAngel(FixedNumber pi)
{
return pi / PI * 180;
}
public static FixedNumber Asin(FixedNumber sin)
{
if (sin < -1 || sin > 1) { return new FixedNumber(); }
if (sin >= 0)
{
return GetAsinTab(sin);
}
else
{
return -GetAsinTab(-sin);
}
}
public static FixedNumber Sin(FixedNumber r)
{
MathFixed math = Instance;
//int tabCount = SinTab.Count*4;
FixedNumber result = new FixedNumber();
r = (r * tabCount / 2 / PI);
//int n = r.ToInt();
while (r < 0)
{
r += tabCount;
}
while (r > tabCount)
{
r -= tabCount;
}
if (r >= 0 && r <= tabCount / 4) // 0 ~ PI/2
{
result = GetSinTab(r);
}
else if (r > tabCount / 4 && r < tabCount / 2) // PI/2 ~ PI
{
r -= new FixedNumber(tabCount / 4);
result = GetSinTab(new FixedNumber(tabCount / 4) - r);
}
else if (r >= tabCount / 2 && r < 3 * tabCount / 4) // PI ~ 3/4*PI
{
r -= new FixedNumber(tabCount / 2);
result = -GetSinTab(r);
}
else if (r >= 3 * tabCount / 4 && r < tabCount) // 3/4*PI ~ 2*PI
{
r = new FixedNumber(tabCount) - r;
result = -GetSinTab(r);
}
return result;
}
public static FixedNumber Abs(FixedNumber ratio)
{
return FixedNumber.Abs(ratio);
}
public static FixedNumber Sqrt(FixedNumber r)
{
return FixedNumber.Sqrt(r);
}
public static FixedNumber Cos(FixedNumber r)
{
return Sin(r + PI / 2);
}
public static FixedNumber SinAngle(FixedNumber angle)
{
return Sin(angle / 180 * PI);
}
public static FixedNumber CosAngle(FixedNumber angle)
{
return Cos(angle / 180 * PI);
}
}
总结
上面做的封装基本还算完善,可以看下代码具体怎么使用。
感谢大家的支持文章来源地址https://www.toymoban.com/news/detail-828772.html
到了这里,关于定点数,定点数二维向量,定点数三维向量,定点数数学类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!