当下有很多超大数值的游戏,就目标的Int或者Int64根本无法够用。所以做了下面的bigFloat,理论支持9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999…(2^31)位数,够用了吧。因为有字符串和循环运算,所以后面要做一个效率的测试。
因为是初版代码没严格测试,可能有很多问题。请慎用。
因为是字符串操作,不建议用来大量计算的使用。但是用作一般频率运算还是可以的。啥是一般频率……呵呵
using System;
/*
* 当下有很多超大数值的游戏,就目标的Int或者Int64根本无法够用。所以做了下面的bigFloat,理论支持9999999999999999999....(2^31)位数,够用了吧。因为有字符串和循环运算,所以后面要做一个效率的测试。
* how to use:
bigInt a0 = (bigFloat)"-0.012345678e1";
bigInt a1 = new bigFloat(1234, -3);
a0 + a1
a0 - a1
a0 * a1
a0 / a1
转载或者使用请勿删除出处
https://blog.csdn.net/thinbug/article/details/100973270
*/
public struct bigFloat
{
//每个单位的进位
//ToString函数的显示格式,目前是26*26+5位数支持,可以自行添加扩充
private static string[] bigUnit = new string[]{ "" , "k" , "m" , "b" , "t",
"aa" , "ab" , "ac" , "ad" , "ae" , "af" , "ag" , "ah" , "ai" , "aj" , "ak" , "al" , "am" , "an" , "ao" , "ap" , "aq" , "ar" , "as" , "at" , "au" , "av" , "aw" , "ax" , "ay" , "az" ,
"ba" , "bb" , "bc" , "bd" , "be" , "bf" , "bg" , "bh" , "bi" , "bj" , "bk" , "bl" , "bm" , "bn" , "bo" , "bp" , "bq" , "br" , "bs" , "bt" , "bu" , "bv" , "bw" , "bx" , "by" , "bz" ,
"ca" , "cb" , "cc" , "cd" , "ce" , "cf" , "cg" , "ch" , "ci" , "cj" , "ck" , "cl" , "cm" , "cn" , "co" , "cp" , "cq" , "cr" , "cs" , "ct" , "cu" , "cv" , "cw" , "cx" , "cy" , "cz" ,
"da" , "db" , "dc" , "dd" , "de" , "df" , "dg" , "dh" , "di" , "dj" , "dk" , "dl" , "dm" , "dn" , "do" , "dp" , "dq" , "dr" , "ds" , "dt" , "du" , "dv" , "dw" , "dx" , "dy" , "dz" ,
"ea" , "eb" , "ec" , "ed" , "ee" , "ef" , "eg" , "eh" , "ei" , "ej" , "ek" , "el" , "em" , "en" , "eo" , "ep" , "eq" , "er" , "es" , "et" , "eu" , "ev" , "ew" , "ex" , "ey" , "ez" ,
"fa" , "fb" , "fc" , "fd" , "fe" , "ff" , "fg" , "fh" , "fi" , "fj" , "fk" , "fl" , "fm" , "fn" , "fo" , "fp" , "fq" , "fr" , "fs" , "ft" , "fu" , "fv" , "fw" , "fx" , "fy" , "fz" ,
"ga" , "gb" , "gc" , "gd" , "ge" , "gf" , "gg" , "gh" , "gi" , "gj" , "gk" , "gl" , "gm" , "gn" , "go" , "gp" , "gq" , "gr" , "gs" , "gt" , "gu" , "gv" , "gw" , "gx" , "gy" , "gz" ,
"ha" , "hb" , "hc" , "hd" , "he" , "hf" , "hg" , "hh" , "hi" , "hj" , "hk" , "hl" , "hm" , "hn" , "ho" , "hp" , "hq" , "hr" , "hs" , "ht" , "hu" , "hv" , "hw" , "hx" , "hy" , "hz" ,
"ia" , "ib" , "ic" , "id" , "ie" , "if" , "ig" , "ih" , "ii" , "ij" , "ik" , "il" , "im" , "in" , "io" , "ip" , "iq" , "ir" , "is" , "it" , "iu" , "iv" , "iw" , "ix" , "iy" , "iz" ,
"ja" , "jb" , "jc" , "jd" , "je" , "jf" , "jg" , "jh" , "ji" , "jj" , "jk" , "jl" , "jm" , "jn" , "jo" , "jp" , "jq" , "jr" , "js" , "jt" , "ju" , "jv" , "jw" , "jx" , "jy" , "jz" ,
"ka" , "kb" , "kc" , "kd" , "ke" , "kf" , "kg" , "kh" , "ki" , "kj" , "kk" , "kl" , "km" , "kn" , "ko" , "kp" , "kq" , "kr" , "ks" , "kt" , "ku" , "kv" , "kw" , "kx" , "ky" , "kz" ,
"la" , "lb" , "lc" , "ld" , "le" , "lf" , "lg" , "lh" , "li" , "lj" , "lk" , "ll" , "lm" , "ln" , "lo" , "lp" , "lq" , "lr" , "ls" , "lt" , "lu" , "lv" , "lw" , "lx" , "ly" , "lz" ,
"ma" , "mb" , "mc" , "md" , "me" , "mf" , "mg" , "mh" , "mi" , "mj" , "mk" , "ml" , "mm" , "mn" , "mo" , "mp" , "mq" , "mr" , "ms" , "mt" , "mu" , "mv" , "mw" , "mx" , "my" , "mz" ,
"na" , "nb" , "nc" , "nd" , "ne" , "nf" , "ng" , "nh" , "ni" , "nj" , "nk" , "nl" , "nm" , "nn" , "no" , "np" , "nq" , "nr" , "ns" , "nt" , "nu" , "nv" , "nw" , "nx" , "ny" , "nz" ,
"oa" , "ob" , "oc" , "od" , "oe" , "of" , "og" , "oh" , "oi" , "oj" , "ok" , "ol" , "om" , "on" , "oo" , "op" , "oq" , "or" , "os" , "ot" , "ou" , "ov" , "ow" , "ox" , "oy" , "oz" ,
"pa" , "pb" , "pc" , "pd" , "pe" , "pf" , "pg" , "ph" , "pi" , "pj" , "pk" , "pl" , "pm" , "pn" , "po" , "pp" , "pq" , "pr" , "ps" , "pt" , "pu" , "pv" , "pw" , "px" , "py" , "pz" ,
"qa" , "qb" , "qc" , "qd" , "qe" , "qf" , "qg" , "qh" , "qi" , "qj" , "qk" , "ql" , "qm" , "qn" , "qo" , "qp" , "qq" , "qr" , "qs" , "qt" , "qu" , "qv" , "qw" , "qx" , "qy" , "qz" ,
"ra" , "rb" , "rc" , "rd" , "re" , "rf" , "rg" , "rh" , "ri" , "rj" , "rk" , "rl" , "rm" , "rn" , "ro" , "rp" , "rq" , "rr" , "rs" , "rt" , "ru" , "rv" , "rw" , "rx" , "ry" , "rz" ,
"sa" , "sb" , "sc" , "sd" , "se" , "sf" , "sg" , "sh" , "si" , "sj" , "sk" , "sl" , "sm" , "sn" , "so" , "sp" , "sq" , "sr" , "ss" , "st" , "su" , "sv" , "sw" , "sx" , "sy" , "sz" ,
"ta" , "tb" , "tc" , "td" , "te" , "tf" , "tg" , "th" , "ti" , "tj" , "tk" , "tl" , "tm" , "tn" , "to" , "tp" , "tq" , "tr" , "ts" , "tt" , "tu" , "tv" , "tw" , "tx" , "ty" , "tz" ,
"ua" , "ub" , "uc" , "ud" , "ue" , "uf" , "ug" , "uh" , "ui" , "uj" , "uk" , "ul" , "um" , "un" , "uo" , "up" , "uq" , "ur" , "us" , "ut" , "uu" , "uv" , "uw" , "ux" , "uy" , "uz" ,
"va" , "vb" , "vc" , "vd" , "ve" , "vf" , "vg" , "vh" , "vi" , "vj" , "vk" , "vl" , "vm" , "vn" , "vo" , "vp" , "vq" , "vr" , "vs" , "vt" , "vu" , "vv" , "vw" , "vx" , "vy" , "vz" ,
"wa" , "wb" , "wc" , "wd" , "we" , "wf" , "wg" , "wh" , "wi" , "wj" , "wk" , "wl" , "wm" , "wn" , "wo" , "wp" , "wq" , "wr" , "ws" , "wt" , "wu" , "wv" , "ww" , "wx" , "wy" , "wz" ,
"xa" , "xb" , "xc" , "xd" , "xe" , "xf" , "xg" , "xh" , "xi" , "xj" , "xk" , "xl" , "xm" , "xn" , "xo" , "xp" , "xq" , "xr" , "xs" , "xt" , "xu" , "xv" , "xw" , "xx" , "xy" , "xz" ,
"ya" , "yb" , "yc" , "yd" , "ye" , "yf" , "yg" , "yh" , "yi" , "yj" , "yk" , "yl" , "ym" , "yn" , "yo" , "yp" , "yq" , "yr" , "ys" , "yt" , "yu" , "yv" , "yw" , "yx" , "yy" , "yz" ,
"za" , "zb" , "zc" , "zd" , "ze" , "zf" , "zg" , "zh" , "zi" , "zj" , "zk" , "zl" , "zm" , "zn" , "zo" , "zp" , "zq" , "zr" , "zs" , "zt" , "zu" , "zv" , "zw" , "zx" , "zy" , "zz"
};
private static int unitMath = 3; //科学计数法来分割3个逗号一个进位
private static int intExtendPower = 6; //后三位int代表小数点,也就是精度,一般6位小数够用了
private static int intExtendMultiply = 1000000; //后6位int代表小数点
private static int intExtendMultiply10 = 10000000; //10就是10,000,000
private Int64 _b ; //小数部分
private int _e ; //指数部分
//direct表示是否要乘以intExtendMultiply,通常外部创建需要direct为false,会乘以小数精度,内部计算直接就使用
public bigFloat(Int64 __b, int __e, bool direct = false)
{
_b = __b * (direct ? 1 : intExtendMultiply);
_e = __e;
if (_b == 0)
_e = 0;
this = bitIntFormat(this);
}
//格式化一个小数,格式必须是1.2345e9 这样的标准格式.
public bigFloat(string str)
{
string __x;
int index = str.ToLower().IndexOf("e");
int dot = str.IndexOf(".");
int i, mult;
int addDot = 0;
if (dot != -1)
{
//如果是小数,首先检查第一个数字是否是0开头,那么就有问题,例如:0.01234e4,要格式化成1.234e2
if (str[dot - 1] == '0' && (dot == 1 || (dot == 2 && str[0] == '-')))
{
for (i = dot + 1; i < str.Length; i++)
{
if (str[i] != '0')
break;
}
addDot = i - dot;
//UnityEngine.Debug.Log(str);
//UnityEngine.Debug.Log("str.Substring(dot + addDot, 1):"+ str.Substring(dot + addDot, 1));
//UnityEngine.Debug.Log("str.Subs):" + str.Substring(dot + addDot + 1, str.Length - (dot + addDot + 1)));
str = str.Substring(0, dot) + str.Substring(dot + addDot, 1) + "." + str.Substring(dot + addDot + 1, str.Length - (dot + addDot + 1));
//UnityEngine.Debug.Log(str);
index = str.ToLower().IndexOf("e");
dot = str.IndexOf(".");
}
}
if (index == -1) //没有e
{
if (dot == -1) //没小数点
{
_b = Int64.Parse(str) * intExtendMultiply;
}
else
{
//整数部分
_b = Int64.Parse(str.Substring(0, dot)) * intExtendMultiply;
//小数部分
__x = str.Substring(dot + 1);
mult = intExtendMultiply / 10;
for (i = 0; i < __x.Length; i++)
{
if(_b >= 0)
_b += Int64.Parse(__x[i].ToString()) * mult;
else
_b -= Int64.Parse(__x[i].ToString()) * mult;
mult = mult / 10;
}
}
_e = 0;
}
else
{
if (dot == -1) //没小数点
{
_b = Int64.Parse(str.Substring(0, index));
}
else
{
//整数部分
_b = Int64.Parse(str.Substring(0, dot)) * intExtendMultiply;
//小数部分
__x = str.Substring(dot + 1, index - (dot + 1));
mult = intExtendMultiply / 10;
for (i = 0; i < __x.Length; i++)
{
if (_b >= 0)
_b += Int64.Parse(__x[i].ToString()) * mult;
else
_b -= Int64.Parse(__x[i].ToString()) * mult;
mult = mult / 10;
}
}
_e = int.Parse(str.Substring(index + 1)) - addDot;
}
if (_b == 0)
_e = 0;
this = bitIntFormat(this);
}
#region Equals(==)
public bool Equals(bigFloat obj)
{
//this非空,obj如果为空,则返回false
if (ReferenceEquals(null, obj)) return false;
//如果为同一对象,必然相等
if (ReferenceEquals(this, obj)) return true;
//如果类型不同,则必然不相等
if (obj.GetType() != this.GetType()) return false;
return obj._b == _b && obj._e == _e;
}
public override bool Equals(object obj)
{
return Equals((bigFloat)obj);
}
//重写==操作符
public static bool operator ==(bigFloat left, bigFloat right)
{
return Equals(left, right);
}
//重写!=操作符
public static bool operator !=(bigFloat left, bigFloat right)
{
return !Equals(left, right);
}
public override int GetHashCode()
{
return _b.GetHashCode() & _e.GetHashCode();
}
#endregion
//隐式转换 : string x = new bigFloat(1,2);
public static implicit operator string(bigFloat rmb)
{
if(rmb._b >= 0)
return string.Format("{0}.{1}e{2}", rmb._b / intExtendMultiply, rmb._b % intExtendMultiply, rmb._e);
else
return string.Format("{0}.{1}e{2}", rmb._b / intExtendMultiply, -rmb._b % intExtendMultiply, rmb._e);
}
//显式转换 : bigInt b = (bigInt)"8e1";
public static explicit operator bigFloat(string str)
{
return new bigFloat(str);
}
//标准格式化
//把类似12345.88转换成1.234588e4这样的标准格式
public static bigFloat bitIntFormat(bigFloat b)
{
//10 -> 1 之间的不用判断了
if (b._b < intExtendMultiply10 && b._b >= intExtendMultiply) return b;
//-10 -> -1之间的不用判断了
if (b._b > -intExtendMultiply10 && b._b <= -intExtendMultiply) return b;
//小于1的,需要改为大于1
string e_str = b._b.ToString("E");
int ifind = e_str.IndexOf("E");
if (ifind == -1)
{
//Debug.LogError("error float(e)" + e_str);
return b;
}
//# 跳过正负符号
//int b = float.Parse(e_str.Substring(0,ifind)); //减去3是因为1000代表1
ifind += 1;
int e = int.Parse(e_str.Substring(ifind)) - intExtendPower; //减去3是因为1000代表1
b._b = (Int64)(b._b * Math.Pow(10, -e));
b._e = b._e + e;
return b;
}
//格式化显示 "323.5k" , "12.34zz"
public override string ToString()
{
int xe = _e % unitMath; //每个单位是3个0
int eabc = _e / unitMath;
string outStr;
Int64 newb = (Int64)(_b * Math.Pow(10, xe));
if (eabc < 0)
eabc = 0;
//判断是否有没小数点
Int64 yu = newb % intExtendMultiply;
int len;
if (yu == 0)
{
if (newb >= 0)
len = 6;
else
len = 7; //负数
outStr = (newb / intExtendMultiply).ToString();
//只获取3位有效数字
outStr = string.Format("{0}{1}", outStr.Substring(0, outStr.Length < len ? outStr.Length : len), bigUnit[eabc]);
}
else
{
if (newb >= 0)
len = 8; //多小数点
else
len = 9; //负数
if (newb >= 0)
outStr = string.Format("{0}.{1}", newb / intExtendMultiply, newb % intExtendMultiply);
else
outStr = string.Format("{0}.{1}", newb / intExtendMultiply, -newb % intExtendMultiply);
//只获取4位有效数字
outStr = string.Format("{0}{1}", outStr.Substring(0, outStr.Length < len ? outStr.Length : len), bigUnit[eabc]);
}
return outStr;
}
public static bigFloat operator +(bigFloat a, bigFloat b)
{
int sube = b._e - a._e;
//超过精度大小了就要返回大的 , 加1是因为还有个整数+小数4位
if (sube > intExtendPower +1)
return new bigFloat(b._b, b._e,true);
else if (sube < -intExtendPower -1)
return new bigFloat(a._b, a._e, true);
int i;
if (sube == 0)
{
//如果两个数的指数相同
return new bigFloat(a._b + b._b, a._e , true);
}
else if (sube >= 0)
{
//如果加的数比较大,把小的数缩小
Int64 num = a._b;
for (i = 0; i < sube; i++)
{
num = num / 10; //一次移动一次小数点
}
return new bigFloat(b._b + num, b._e, true);
}
else
{
//如果加的数比较小,把小的数缩小
Int64 num = b._b;
for (i = sube; i < 0; i++)
{
num = num / 10; //一次移动一次小数点
}
return new bigFloat(a._b + num, a._e, true);
}
}
public static bigFloat operator -(bigFloat a, bigFloat b)
{
b._b = -b._b;
return a + b;
}
public static bigFloat operator *(bigFloat a, bigFloat b) {
a._b = a._b * b._b;
a._e = a._e + b._e;
return bitIntFormat(a);
}
public static bigFloat operator /(bigFloat a, bigFloat b) {
a._b = a._b / b._b;
a._e = a._e - b._e;
return bitIntFormat(a);
}
public static bool operator <(bigFloat a, bigFloat b) {
if (a._e == b._e)
{
if (a._b < b._e)
return true;
else
return false;
}
else if (a._e < b._e)
{
return true;
}
else
{
return false;
}
}
public static bool operator <=(bigFloat a, bigFloat b)
{
if (a._e == b._e)
{
if (a._b <= b._e)
return true;
else
return false;
}
else if (a._e < b._e)
{
return true;
}
else
{
return false;
}
}
public static bool operator >(bigFloat a, bigFloat b) {
if (a <= b)
return false;
return true;
}
public static bool operator >=(bigFloat a, bigFloat b) {
if (a < b)
return false;
return true;
}
}
如果用C#来做,其实可以用System.Numerics的BigInteger来做,可能效率更好一些。
后面有时间用这个来做一个精度和运算效率更好的。
BigInteger参考
https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger?view=netframework-4.8