自己做的一个c#超大浮点数bigFloat

26 篇文章 0 订阅

当下有很多超大数值的游戏,就目标的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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值