用科学计数法表示大数字的类
日期: 2016-05-04 分类: 0o下载吧o0 1509次阅读
由于某些游戏必须使用很大的数字单位来显示内容超过了c#值类型最大承受能力所以在此封装一个科学计数法表示数值的类和支持自定义单位显示。
[Serializable]
public struct Money
{
const int cfg_UnitBit = 3; //进位
public float x;
public int n;
public Money(int param)
{
CalcXN(param, out x, out n);
}
public Money(float param)
{
CalcXN(param, out x, out n);
}
public Money(string param)
{
x = 0;
n = 0;
var unit = Regex.Replace(param, "[0-9]", "", RegexOptions.IgnoreCase).Replace(".", "");
var Num = Regex.Replace(param, "[a-z]", "", RegexOptions.IgnoreCase);
if (float.TryParse(Num, out x))
{
var rn = MoneyUnit.FindIndex(unit) * cfg_UnitBit;
CalcXN(x, out x, out n);
n += rn;
}
}
public Money(float a, float pow)
{
if(a == 0)
{
n = 0;
x = 0;
}
else if (pow == 0)
{
n = 0;
x = a == 0 ? 0 : 1;
}
else
{
var rn = Mathf.Log10(a) * pow;
var nPow = (int)rn;
x = Mathf.Pow(10, rn - (int)rn);
CalcXN(x, out x, out n);
n += nPow;
}
}
/// <summary>
/// 根据单位初始化 a^n
/// </summary>
/// <param name="a"></param>
/// <param name="unit">单位</param>
/// <param name="bit">进位</param>
public Money(float a, int unit, int bit = cfg_UnitBit)
{
unit *= bit;
if (a == 0)
{
n = 0;
x = 0;
}
else
{
CalcXN(a, out x, out n);
n += unit;
}
}
//慎用 会发生异常
public int ToInt()
{
return (int)ToFloat();
}
//慎用 会发生异常
public float ToFloat()
{
return x * Mathf.Pow(10, n);
}
public override string ToString()
{
if (n > 0)
{
int unit = n / cfg_UnitBit;
int last = n % cfg_UnitBit;
var unitStr = MoneyUnit.GetUnit(unit, out unit);
var result = string.Empty;
if (unit > 30f/ cfg_UnitBit)
{
result = x.ToString().Replace(".", "");
result = result.PadRight(result.Length - 1 + last + unit * cfg_UnitBit,'0');
}
else
{
result = (x * Mathf.Pow(10, last + unit * cfg_UnitBit)).ToString("f2");
}
return (result + unitStr).TrimEnd('0').Trim('.');
}
else if(n == 0 && x >= 1f)
{
return x.ToString("f2");
}
return ToFloat().ToString("f38").TrimEnd('0').Trim('.');
}
public static Money Pow(Money x1, int pow)
{
var x = new Money(x1.x, pow);
var n = x1.n + pow;
x.n += n;
return x;
}
//a^n + b^m = (10^(nloga-n) + 10^(mlogb-n)) * 10^n
//a^n + b^m = (10^(nloga-n) + 10^(mlogb-m) * 10^(m-n)) * 10^n
//a^n + b^m = (xa + xb * 10^(nb-na)) * 10^na
public static Money operator +(Money x1, Money x2)
{
var a1 = x1.x;
var a2 = x2.x;
var n1 = x1.n;
var n2 = x2.n;
var nMax = Mathf.Max(n1, n2);
var nMin = Mathf.Min(n1, n2);
var nDelta = Mathf.Abs(n1 - n2);
if (nDelta >= 38)
{//越界处理
if (n1 == nMax)
{
return x1;
}
else
{
return x2;
}
}
else
{
Money result = new Money();
if (nDelta == 0)
{
result.x = a1 + a2;
CalcXN(result.x, out result.x, out result.n);
result.n += n1;
}
else if (n1 == nMax)
{
if(nDelta > 5)
{
result.x = (int)a1 * Mathf.Pow(10, nDelta) + (int)a2;
}
else
{
result.x = a1 * Mathf.Pow(10, nDelta) + a2;
}
CalcXN(result.x, out result.x, out result.n);
result.n += n2;
}
else
{
//if (nDelta > 5)
//{
// result.x = (int)a2 * Mathf.Pow(10, nDelta) + (int)a1;
//}
//else
//{
// result.x = a2 * Mathf.Pow(10, nDelta) + a1;
//}
result.x = a2 * Mathf.Pow(10, nDelta) + a1;
CalcXN(result.x, out result.x, out result.n);
result.n += n1;
}
return result;
}
}
//a^n - b^m = (xa - xb * 10^(nb-na)) * 10^na
public static Money operator -(Money x1, Money x2)
{
return x1 + (x2 * -1);
}
//a^n * b^m = 10^(nloga+mlogb)
//a^n * b^m = xa * xb * 10^(na + nb)
public static Money operator *(Money x1, Money x2)
{
var rx = x1.x * x2.x;
var rn = x1.n + x2.n;
Money result = new Money();
CalcXN(rx, out result.x, out result.n);
result.n += rn;
return result;
}
//a^n / b^m = xa / xb * 10^(na - nb)
public static Money operator /(Money x1, Money x2)
{
if (x2.x == 0)
{
return float.NaN;
}
var rx = x1.x / x2.x;
var rn = x1.n - x2.n;
Money result = new Money();
CalcXN(rx, out result.x, out result.n);
result.n += rn;
return result;
}
public static Money operator +(Money x1, float x2)
{
return x1 + new Money(x2);
}
public static Money operator +(Money x1, int x2)
{
return x1 + new Money(x2);
}
public static Money operator -(Money x1, float x2)
{
return x1 - new Money(x2);
}
public static Money operator -(Money x1, int x2)
{
return x1 - new Money(x2);
}
public static Money operator -(float x1, Money x2)
{
return new Money(x1) - x2;
}
public static Money operator -(int x1, Money x2)
{
return new Money(x1) - x2;
}
public static Money operator *(Money x1, float x2)
{
return x1 * new Money(x2);
}
public static Money operator *(Money x1, int x2)
{
return x1 * new Money(x2);
}
public static Money operator /(Money x1, float x2)
{
return x1 / new Money(x2);
}
public static Money operator /(Money x1, int x2)
{
return x1 / new Money(x2);
}
public static Money operator /(float x1, Money x2)
{
return new Money(x1) / x2;
}
public static Money operator /(int x1, Money x2)
{
return new Money(x1) / x2;
}
public static bool operator >(Money x1, Money x2)
{
if (x1.x * x2.x > 0)
{
if (x1.n == x2.n)
{
return x1.x > x2.x;
}
else
{
return x1.x > 0 ? x1.n > x2.n : x1.n < x2.n;
}
}
else if (x1.x * x2.x < 0)
{
return x1.x > 0;
}
else
{
if (x1.x == 0)
{
return x2.x < 0;
}
else
{
return x1.x > 0;
}
}
}
public static bool operator <(Money x1, Money x2)
{
if (x1.x * x2.x > 0)
{
if (x1.n == x2.n)
{
return x1.x < x2.x;
}
else
{
return x1.x > 0 ? x1.n < x2.n : x1.n > x2.n;
}
}
else if (x1.x * x2.x < 0)
{
return x1.x < 0;
}
else
{
if (x1.x == 0)
{
return x2.x > 0;
}
else
{
return x1.x < 0;
}
}
}
public static bool operator >=(Money x1, Money x2)
{
if (x1.x * x2.x > 0)
{
if (x1.n == x2.n)
{
return x1.x >= x2.x;
}
else
{
return x1.x > 0 ? x1.n >= x2.n : x1.n <= x2.n;
}
}
else if (x1.x * x2.x < 0)
{
return x1.x > 0;
}
else
{
if (x1.x == 0)
{
return x2.x <= 0;
}
else
{
return x1.x >= 0;
}
}
}
public static bool operator <=(Money x1, Money x2)
{
if (x1.x * x2.x > 0)
{
if (x1.n == x2.n)
{
return x1.x <= x2.x;
}
else
{
return x1.x > 0 ? x1.n <= x2.n : x1.n >= x2.n;
}
}
else if (x1.x * x2.x < 0)
{
return x1.x < 0;
}
else
{
if (x1.x == 0)
{
return x2.x >= 0;
}
else
{
return x1.x <= 0;
}
}
}
public static bool operator ==(Money x1, Money x2)
{
return Mathf.Abs(x1.x - x2.x) <= 0.000001f && x1.n == x2.n;
}
public static bool operator !=(Money x1,Money x2)
{
return Mathf.Abs(x1.x - x2.x) > 0.000001f || x1.n != x2.n;
}
public static implicit operator Money(int x)
{
return new Money(x);
}
public static implicit operator Money(float x)
{
return new Money(x);
}
public static implicit operator Money(string x)
{
return new Money(x);
}
public static implicit operator int(Money x)
{
return x.ToInt();
}
public static implicit operator float(Money x)
{
return x.ToFloat();
}
public static implicit operator string(Money x)
{
return x.ToString();
}
static void CalcXN(float param, out float x, out int n)
{
x = 0;
n = 0;
var s = param.ToString("f38").TrimEnd('0');
var str = s.Split('.');
if (param >= 1 || param <= -1)
{
int count = str[0].Length;
x = param / Mathf.Pow(10, count - 1);
n = count - 1;
}
else
{
var flag = param >= 0 ? 1 : -1;
for (int i = 0; i < str[1].Length; ++i)
{
if (str[1][i] != '0')
{
var resultstr = str[1].Substring(i, str[1].Length - i).Insert(1, ".");
x = float.Parse(resultstr) * flag;
n = -(i + 1);
break;
}
}
}
}
static void CalcXN(int param, out float x, out int n)
{
int count = param.ToString().Length;
var result = (param / Mathf.Pow(10, count - 1));
x = float.Parse(result.ToString());
n = count - 1;
}
public override bool Equals(object obj)
{
if (!(obj is Money))
{
return false;
}
var money = (Money)obj;
return x == money.x &&
n == money.n;
}
public override int GetHashCode()
{
var hashCode = 1217719504;
hashCode = hashCode * -1521134295 + x.GetHashCode();
hashCode = hashCode * -1521134295 + n.GetHashCode();
return hashCode;
}
}
public static class MoneyUnit
{
static bool HasInit
{
get; set;
} = false;
static Dictionary<int, string> UnitDict = new Dictionary<int, string>();
public static void InitUnit()
{
if(!HasInit)
{
UnitDict.Clear();
自定义单位我进行了读表操作 大家可以自行更改
var list = TableMgr.GetInstance().GetUnitDescList();
for(int i = 0; i < list.Count; ++i)
{
UnitDict[list[i].id] = list[i].unitName;
}
}
HasInit = true;
}
/// <summary>
/// 获取单位
/// </summary>
/// <param name="index">当前位数</param>
/// <param name="LastUnitIndex">剩余位数</param>
/// <returns></returns>
public static string GetUnit(int index,out int LastUnitIndex)
{
InitUnit();
string result = "0";
LastUnitIndex = 0;
if(!UnitDict.TryGetValue(index,out result))
{
var last = UnitDict.OrderBy(p => p.Key).Last();
result = last.Value;
LastUnitIndex = index - last.Key;
}
return result;
}
/// <summary>
/// 按单位查找index
/// </summary>
/// <param name="unit"></param>
/// <returns></returns>
public static int FindIndex(string unit)
{
InitUnit();
var result = UnitDict.Where(p => p.Value == unit);
if(result != null && result.Count() > 0)
{
return result.First().Key;
}
return 0;
}
public static Money Pow(this Money x1,int unit)
{
return Money.Pow(x1, unit);
}
}
自定义单位显示我是读表操作的 大家可以自行更改填充UnitDict
源码下载链接:
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
上一篇: 奇幻建筑模型
精华推荐
