Пример #1
0
        public override object Clone()
        {
            RBignum big = new RBignum(ruby, len, sign);

            Array.Copy(digits, big.digits, len);
            return(big);
        }
Пример #2
0
        static private RBignum to_big(NetRuby ruby, object o)
        {
            RBignum y = null;

            if (o is RFixnum)
            {
                o = ((RFixnum)o).GetData();
            }
            if (o is RBignum)
            {
                y = (RBignum)o;
            }
            if (o is int)
            {
                y = Int2Big(ruby, (int)o);
            }
            else if (o is long)
            {
                y = Long2Big(ruby, (long)o);
            }
            else if (o is double)
            {
                y = Dbl2Big(ruby, (double)o);
            }
            else if (o is RFloat)
            {
                y = Dbl2Big(ruby, ((RFloat)o).Double);
            }
            return(y);
        }
Пример #3
0
        public static RBignum operator %(RBignum x, RBignum y)
        {
            RBignum mod;
            RBignum div = x.divrem(y, out mod);

            return(mod);
        }
Пример #4
0
        public override RNumeric Divide(object o)
        {
            RBignum z;
            RBignum y = divmod(o, out z);

            return(y.Normalize);
        }
Пример #5
0
        public override RArray DivMod(object o)
        {
            RBignum z;
            RBignum y = divmod(o, out z);

            return(RArray.AssocNew(ruby, y.Normalize, z.Normalize));
        }
Пример #6
0
        private RBignum sub(RBignum y)
        {
            uint[] xx   = digits;
            uint[] yy   = y.digits;
            int    xlen = len;
            int    ylen = y.len;
            bool   sig  = true;
            int    i;

            if (len < y.len)
            {
                xx   = y.digits;
                yy   = digits;
                sig  = false;
                xlen = y.len;
                ylen = len;
            }
            else if (len == y.len)
            {
                for (i = len; i > 0;)
                {
                    i--;
                    if (xx[i] > yy[i])
                    {
                        break;
                    }
                    if (xx[i] < yy[i])
                    {
                        xx   = y.digits;
                        yy   = digits;
                        xlen = y.len;
                        ylen = len;
                        sig  = false;
                    }
                }
            }
            uint[] z   = new uint[xlen];
            long   num = 0;

            for (i = 0; i < ylen; i++)
            {
                num += (long)xx[i] - yy[i];
                z[i] = BIGLO(num);
                num  = BIGDN(num);
            }
            while (num != 0 && i < xlen)
            {
                num   += xx[i];
                z[i++] = BIGLO(num);
                num    = BIGDN(num);
            }
            while (i < xlen)
            {
                z[i] = xx[i];
                i++;
            }
            return(new RBignum(ruby, z, sig));
        }
Пример #7
0
        public static RBignum Ulong2Big(NetRuby ruby, ulong n)
        {
            ulong   num = (ulong)n;
            RBignum big = new RBignum(ruby, 2, true);

            big.digits[0] = (uint)n;
            big.digits[1] = (uint)(n >> 32);
            return(big);
        }
Пример #8
0
        public static RBignum Uint2Big(NetRuby ruby, uint n)
        {
            RBignum big = new RBignum(ruby, 1, true);

            big.digits[0] = n;
            if (n == 0)
            {
                big.len = 0;
            }
            return(big);
        }
Пример #9
0
        private RBignum add(RBignum y, bool s)
        {
            bool sig = (s == y.sign);

            if (sign != sig)
            {
                if (sig)
                {
                    return(y.sub(this));
                }
                return(sub(y));
            }
            uint[] xx   = digits;
            uint[] yy   = y.digits;
            int    xlen = len;
            int    ylen = y.len;
            int    nl   = len;

            if (nl > y.len)
            {
                nl++;
                xx   = y.digits;
                yy   = digits;
                xlen = y.len;
                ylen = len;
            }
            else
            {
                nl = y.len + 1;
            }
            uint[] z   = new uint[nl];
            ulong  num = 0;
            int    i;

            for (i = 0; i < xlen; i++)
            {
                num += (ulong)xx[i] + (ulong)yy[i];
                z[i] = BIGLO(num);
                num  = BIGDN(num);
            }
            while (num != 0 && i < ylen)
            {
                num   += yy[i];
                z[i++] = BIGLO(num);
                num    = BIGDN(num);
            }
            while (i < ylen)
            {
                z[i] = yy[i];
                i++;
            }
            z[i] = (uint)num;
            return(new RBignum(ruby, z, sig));
        }
Пример #10
0
 static internal RInteger ToInteger(NetRuby ruby, double d)
 {
     if (d <= Int32.MaxValue && d >= Int32.MinValue)
     {
         return(new RFixnum(ruby, (int)d));
     }
     else if (d <= Int64.MaxValue && d >= Int64.MinValue)
     {
         return(new RBignum(ruby, (long)d));
     }
     return(RBignum.Dbl2Big(ruby, d));
 }
Пример #11
0
        public override bool LE(object o)
        {
            RBignum r = to_big(ruby, o);

            if (r == null)
            {
                return((bool)CoerceBin(o));
            }
            int i = CompareTo(r);

            return(i <= 0);
        }
Пример #12
0
        private RBignum divmod(object o, out RBignum mod)
        {
            mod = null;
            RBignum y  = to_big(ruby, o);
            RBignum dv = divrem(y, out mod);

            if (sign != y.sign && mod.len > 0)
            {
                dv  = dv - to_big(ruby, 1);
                mod = mod + y;
            }
            return(dv);
        }
Пример #13
0
        public bool Eq(object o)
        {
            RBignum y = null;

            if (o is RFixnum)
            {
                o = ((RFixnum)o).GetData();
            }
            if (o is int)
            {
                y = Int2Big(ruby, (int)o);
            }
            else if (o is long)
            {
                y = Long2Big(ruby, (long)o);
            }
            else if (o is double)
            {
                return(Big2Dbl() == (double)o);
            }
            else if (o is RFloat)
            {
                return(Big2Dbl() == ((RFloat)o).Double);
            }
            else if (o is RBignum == false)
            {
                return(false);
            }
            else
            {
                y = (RBignum)o;
            }
            if (sign != y.sign)
            {
                return(false);
            }
            if (len != y.len)
            {
                return(false);
            }
            for (int i = 0; i < len; i++)
            {
                if (digits[i] != y.digits[i])
                {
                    return(false);
                }
            }
            return(true);
        }
Пример #14
0
        public static RBignum Int2Big(NetRuby ruby, int n)
        {
            bool neg = false;

            if (n < 0)
            {
                n   = -n;
                neg = true;
            }
            RBignum big = Uint2Big(ruby, (uint)n);

            if (neg)
            {
                big.sign = false;
            }
            return(big);
        }
Пример #15
0
        public static RBignum Long2Big(NetRuby ruby, long n)
        {
            bool neg = false;

            if (n < 0)
            {
                n   = -n;
                neg = true;
            }
            RBignum big = Ulong2Big(ruby, (ulong)n);

            if (neg)
            {
                big.sign = false;
            }
            return(big);
        }
Пример #16
0
        public RInteger Negate()
        {
            RBignum z = (RBignum)Clone();

            if (sign == false)
            {
                z.TwoComp();
            }
            for (int i = 0; i < len; i++)
            {
                z.digits[i] = ~z.digits[i];
            }
            if (sign)
            {
                z.TwoComp();
            }
            z.sign = !z.sign;
            return(z.Normalize);
        }
Пример #17
0
        public int CompareTo(object o)
        {
            RBignum r = to_big(ruby, o);

            if (r == null)
            {
                throw new ArgumentException("object is not a Bignum");
            }
            if (sign && !r.sign)
            {
                return(1);
            }
            if (!sign && r.sign)
            {
                return(-1);
            }
            if (len < r.len)
            {
                return((sign) ? -1 : 1);
            }
            if (len > r.len)
            {
                return((sign) ? 1 : -1);
            }
            int xlen = len;

            while ((xlen-- > 0) && digits[xlen] == r.digits[xlen])
            {
                ;
            }
            if (xlen < 0)
            {
                return(0);
            }
            return((digits[xlen] > r.digits[xlen]) ? (sign ? 1 : -1) : (sign ? -1 : 1));
        }
Пример #18
0
        private RBignum divrem(RBignum y, out RBignum mod)
        {
            mod = null;
            uint dd;
            int ny = y.len;
            int nx = len;
            int i;
            ulong t2;
            if (ny == 0 && y.digits[0] == 0)
                throw new DivideByZeroException("divided by 0");
            if (nx < ny || nx == ny && digits[nx - 1] < y.digits[ny - 1])
            {
                mod = this;
                return new RBignum(ruby, (uint)0, true);
            }
            if (ny == 1)
            {
                dd = y.digits[0];
                RBignum z = (RBignum)Clone();
                i = nx;
                t2 = 0;
                while (i-- != 0)
                {
                    t2 = (ulong)BIGUP(t2) + z.digits[i];
                    z.digits[i] = (uint)(t2 / dd);
                    t2 %= dd;
                }
                z.sign = (sign == y.sign);
                mod = Uint2Big(ruby, (uint)t2);
                mod.sign = sign;
                return z;
            }
        
            uint[] zz = new uint[(nx == ny) ? nx + 2 : nx + 1];
            if (nx == ny) zz[nx + 1] = 0;
            while (y.digits[ny - 1] == 0) ny--;
        
            dd = 0;
            uint q = y.digits[ny - 1];
            int j = 0;
            uint[] ys = y.digits;
            while ((q & ((uint)1 << (int)(BITSPERDIG-1))) == 0)
            {
                q <<= 1;
                dd++;
            }
            if (dd != 0)
            {
                RBignum yy = (RBignum)y.Clone();
                j = 0;
                t2 = 0;
                while (j < ny)
                {
                    t2 += ((ulong)y.digits[j]) << (int)dd;
                    yy.digits[j++] = BIGLO(t2);
                    t2 = BIGDN(t2);
                }
                ys = yy.digits;
                j = 0;
                t2 = 0;
                while (j < nx)
                {
                    t2 += ((ulong)digits[j]) << (int)dd;
                    zz[j++] = BIGLO(t2);
                    t2 = BIGDN(t2);
                }
                zz[j] = (uint)t2;
            }
            else
            {
                zz[nx] = 0;
                j = nx;
                while (j-- != 0) zz[j] = digits[j];
            }

            j = (nx == ny) ? nx + 1 : nx;
            do
            {
                if (zz[j] == ys[ny - 1]) q = (uint)(BIGRAD - 1);
                else q = (uint)((BIGUP(zz[j]) + zz[j - 1])/ys[ny - 1]);
                if (q != 0)
                {
                    i = 0;
                    long num = 0;
                    t2 = 0;
                    do
                    {
                        t2 += (ulong)ys[i] * q;
                        ulong ee = (ulong)(num - BIGLO(t2));
                        num = (long)(zz[j - ny + i] + ee);
                        if (ee != 0) zz[j - ny + i] = BIGLO(num);
                        num = BIGDN(num);
                        t2 = BIGDN(t2);
                    }
                    while (++i < ny);
                    num += (long)(zz[j - ny + i] - t2);
                    while (num != 0)
                    {
                        i = 0;
                        num = 0;
                        q--;
                        do
                        {
                            ulong ee = (ulong)(num + ys[i]);
                            num = (long)((ulong)zz[j - ny + i] + ee);
                            if (ee != 0) zz[j - ny + i] = BIGLO(num);
                            num = BIGDN(num);
                        }
                        while (++i < ny);
                        num--;
                    }
                }
                zz[j] = q;
            }
            while (--j >= ny);
            RBignum div = new RBignum(ruby, zz, sign == y.sign);
            mod = (RBignum)div.Clone();
            j = (nx == ny ? nx + 2 : nx + 1) - ny;
            for (i = 0; i < j; i++) div.digits[i] = div.digits[i + ny];
            div.len = i;
        
            while (ny-- != 0 && mod.digits[ny] == 0);
            ny++;
            if (dd != 0)
            {
                t2 = 0;
                i = ny;
                while (i-- != 0)
                {
                    t2 = (t2 | mod.digits[i]) >> (int)dd;
                    q = mod.digits[i];
                    mod.digits[i] = BIGLO(t2);
                    t2 = BIGUP(q);
                }
                mod.len = ny;
                mod.sign = sign;
            }
            return div;
        }
Пример #19
0
 private RBignum add(RBignum y, bool s)
 {
     bool sig = (s == y.sign);
     if (sign != sig)
     {
         if (sig) return y.sub(this);
         return sub(y);
     }
     uint[] xx = digits;
     uint[] yy = y.digits;
     int xlen = len;
     int ylen = y.len;
     int nl = len;
     if (nl > y.len)
     {
         nl++;
         xx = y.digits;
         yy = digits;
         xlen = y.len;
         ylen = len;
     }
     else
     {
         nl = y.len + 1;
     }
     uint[] z = new uint[nl];
     ulong num = 0;
     int i;
     for (i = 0; i < xlen; i++)
     {
         num += (ulong)xx[i] + (ulong)yy[i];
         z[i] = BIGLO(num);
         num = BIGDN(num);
     }
     while (num != 0 && i < ylen)
     {
         num += yy[i];
         z[i++] = BIGLO(num);
         num = BIGDN(num);
     }
     while (i < ylen)
     {
         z[i] = yy[i];
         i++;
     }
     z[i] = (uint)num;
     return new RBignum(ruby, z, sig);
 }
Пример #20
0
 private RBignum sub(RBignum y)
 {
     uint[] xx = digits;
     uint[] yy = y.digits;
     int xlen = len;
     int ylen = y.len;
     bool sig = true;
     int i;
     if (len < y.len)
     {
         xx = y.digits;
         yy = digits;
         sig = false;
         xlen = y.len;
         ylen = len;
     }
     else if (len == y.len)
     {
         for (i = len; i > 0; )
         {
             i--;
             if (xx[i] > yy[i])
                 break;
             if (xx[i] < yy[i])
             {
                 xx = y.digits;
                 yy = digits;
                 xlen = y.len;
                 ylen = len;
                 sig = false;
             }
         }
     }
     uint[] z = new uint[xlen];
     long num = 0;
     for (i = 0; i < ylen; i++)
     {
         num += (long)xx[i] - yy[i];
         z[i] = BIGLO(num);
         num = BIGDN(num);
     }
     while (num != 0 && i < xlen)
     {
         num += xx[i];
         z[i++] = BIGLO(num);
         num = BIGDN(num);
     }
     while (i < xlen)
     {
         z[i] = xx[i];
         i++;
     }
     return new RBignum(ruby, z, sig);
 }
Пример #21
0
 private RBignum divmod(object o, out RBignum mod)
 {
     mod = null;
     RBignum y = to_big(ruby, o);
     RBignum dv = divrem(y, out mod);
     if (sign != y.sign && mod.len > 0)
     {
         dv = dv - to_big(ruby, 1);
         mod = mod + y;
     }
     return dv;
 }
Пример #22
0
 public static RBignum Ulong2Big(NetRuby ruby, ulong n)
 {
     ulong num = (ulong)n;
     RBignum big = new RBignum(ruby, 2, true);
     big.digits[0] = (uint)n;
     big.digits[1] = (uint)(n >> 32);
     return big;
 }
Пример #23
0
 public static RBignum Uint2Big(NetRuby ruby, uint n)
 {
     RBignum big = new RBignum(ruby, 1, true);
     big.digits[0] = n;
     if (n == 0) big.len = 0;
     return big;
 }
Пример #24
0
        internal static object StringToInteger(NetRuby ruby, string astr, int radix)
        {
            RBignum z = null;
            bool badcheck = (radix == 0) ? true : false;
            string str = astr.Trim().ToUpper().Replace("_", "");
            bool sign = true;
            int idx = 0;
            if (astr.Length == 1)
            {
                return Convert.ToInt32(str);
            }
            if (str[0] == '+')
            {
                idx++;
            }
            else if (str[0] == '-')
            {
                idx++;
                sign = false;
            }
            if (str[idx] == '+' || str[idx] == '-')
            {
                if (badcheck) goto bad;
                return 0;
            }
            if (radix == 0)
            {
                if (str[idx] == '0' && (idx + 1) < str.Length)
                {
                    char c = str[idx + 1];
                    if (c == 'X')
                    {
                        radix = 16;
                    }
                    else if (c == 'B')
                    {
                        radix = 2;
                    }
                    else
                    {
                        radix = 8;
                    }
                }
                else
                {
                    radix = 10;
                }
            }
            int len = str.Length;
            if (radix == 8)
            {
                while (idx < str.Length && str[idx] == '0') idx++;
                if (idx == str.Length) return 0;
                str = str.Substring(idx);
                len = 3 * str.Length;
            }
            else
            {
                if (radix == 16 && str[idx] == '0' && str[idx + 1] == 'X')
                    idx += 2;
                else if (radix == 2 && str[idx] == '0' && str[idx + 1] == 'B')
                    idx += 2;
                while (idx < str.Length && str[idx] == '0') idx++;
                if (idx == str.Length)
                {
                    if (badcheck) goto bad;
                    return 0;
                }
                str = str.Substring(idx);
                len = 4 * str.Length;
            }
            uint x;
            if (len <= 32)
            {
                try
                {
                    x = Convert.ToUInt32(str, radix);
                    if (x > (uint)Int32.MaxValue)
                    {
                        return new RBignum(ruby, x, sign);
                    }
                    else
                    {
                        int xx = (int)x;
                        return (sign) ? xx : -xx;
                    }
                }
                catch (OverflowException)
                {
                    ;
                }
                catch
                {
                    goto bad;
                }
            }

            len = (int)(len / BITSPERDIG) + 1;
            uint[] zds = new uint[len];
            int blen = 1;
            for (idx = 0; idx < str.Length; idx++)
            {
                char c = str[idx];
                switch (c)
                {
                case '8':
                case '9':
                    if (radix == 8)
                    {
                        c = (char)radix;
                        break;
                    }
                    goto case '0';
                case '7': case '6': case '5': case '4':
                case '3': case '2': case '1': case '0':
                    c = (char)(c - '0');
                    break;
                case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
                    if (radix != 16) c = (char)radix;
                    else c = (char)(c - 'A' + 10);
                    break;
                default:
                    c = (char)radix;
                    break;
                }
                if (c >= radix) break;
                int i = 0;
                ulong num = c;
                for (;;)
                {
                    while (i < blen)
                    {
                        num += (ulong)zds[i] * (ulong)radix;
                        zds[i++] = BIGLO(num);
                        num = BIGDN(num);
                    }
                    if (num != 0)
                    {
                        blen++;
                        continue;
                    }
                    break;
                }
            }
            z = new RBignum(ruby, zds, sign);
            return z;
        
        bad:
            throw new eArgError("Invalid value for Integer: \"" + astr + "\"");
        }
Пример #25
0
        internal static object StringToInteger(NetRuby ruby, string astr, int radix)
        {
            RBignum z        = null;
            bool    badcheck = (radix == 0) ? true : false;
            string  str      = astr.Trim().ToUpper().Replace("_", "");
            bool    sign     = true;
            int     idx      = 0;

            if (astr.Length == 1)
            {
                return(Convert.ToInt32(str));
            }
            if (str[0] == '+')
            {
                idx++;
            }
            else if (str[0] == '-')
            {
                idx++;
                sign = false;
            }
            if (str[idx] == '+' || str[idx] == '-')
            {
                if (badcheck)
                {
                    goto bad;
                }
                return(0);
            }
            if (radix == 0)
            {
                if (str[idx] == '0' && (idx + 1) < str.Length)
                {
                    char c = str[idx + 1];
                    if (c == 'X')
                    {
                        radix = 16;
                    }
                    else if (c == 'B')
                    {
                        radix = 2;
                    }
                    else
                    {
                        radix = 8;
                    }
                }
                else
                {
                    radix = 10;
                }
            }
            int len = str.Length;

            if (radix == 8)
            {
                while (idx < str.Length && str[idx] == '0')
                {
                    idx++;
                }
                if (idx == str.Length)
                {
                    return(0);
                }
                str = str.Substring(idx);
                len = 3 * str.Length;
            }
            else
            {
                if (radix == 16 && str[idx] == '0' && str[idx + 1] == 'X')
                {
                    idx += 2;
                }
                else if (radix == 2 && str[idx] == '0' && str[idx + 1] == 'B')
                {
                    idx += 2;
                }
                while (idx < str.Length && str[idx] == '0')
                {
                    idx++;
                }
                if (idx == str.Length)
                {
                    if (badcheck)
                    {
                        goto bad;
                    }
                    return(0);
                }
                str = str.Substring(idx);
                len = 4 * str.Length;
            }
            uint x;

            if (len <= 32)
            {
                try
                {
                    x = Convert.ToUInt32(str, radix);
                    if (x > (uint)Int32.MaxValue)
                    {
                        return(new RBignum(ruby, x, sign));
                    }
                    else
                    {
                        int xx = (int)x;
                        return((sign) ? xx : -xx);
                    }
                }
                catch (OverflowException)
                {
                    ;
                }
                catch
                {
                    goto bad;
                }
            }

            len = (int)(len / BITSPERDIG) + 1;
            uint[] zds  = new uint[len];
            int    blen = 1;

            for (idx = 0; idx < str.Length; idx++)
            {
                char c = str[idx];
                switch (c)
                {
                case '8':
                case '9':
                    if (radix == 8)
                    {
                        c = (char)radix;
                        break;
                    }
                    goto case '0';

                case '7':
                case '6':
                case '5':
                case '4':
                case '3':
                case '2':
                case '1':
                case '0':
                    c = (char)(c - '0');
                    break;

                case 'A':
                case 'B':
                case 'C':
                case 'D':
                case 'E':
                case 'F':
                    if (radix != 16)
                    {
                        c = (char)radix;
                    }
                    else
                    {
                        c = (char)(c - 'A' + 10);
                    }
                    break;

                default:
                    c = (char)radix;
                    break;
                }
                if (c >= radix)
                {
                    break;
                }
                int   i   = 0;
                ulong num = c;
                for (;;)
                {
                    while (i < blen)
                    {
                        num     += (ulong)zds[i] * (ulong)radix;
                        zds[i++] = BIGLO(num);
                        num      = BIGDN(num);
                    }
                    if (num != 0)
                    {
                        blen++;
                        continue;
                    }
                    break;
                }
            }
            z = new RBignum(ruby, zds, sign);
            return(z);

bad:
            throw new eArgError("Invalid value for Integer: \"" + astr + "\"");
        }
Пример #26
0
 public override object Clone()
 {
     RBignum big = new RBignum(ruby, len, sign);
     Array.Copy(digits, big.digits, len);
     return big;
 }
Пример #27
0
        internal static object sprintf(RBasic r, params object[] args)
        {
            NetRuby ruby = r.ruby;

            PFlag  flags   = PFlag.NONE;
            bool   tainted = false;
            object ofmt;
            int    nextarg = getarg(args, 0, out ofmt);

            if (ofmt is RBasic)
            {
                tainted = ((RBasic)ofmt).IsTainted;
            }
            string fmt = ofmt.ToString();
            string result = String.Empty;
            int    width, prec;

            for (int i = 0; i < fmt.Length; i++)
            {
                int n, ix;
                for (ix = i; ix < fmt.Length && fmt[ix] != '%'; ix++)
                {
                    ;
                }
                result += fmt.Substring(i, ix - i);
                if (ix >= fmt.Length)
                {
                    break;
                }
                i     = ix + 1;
                width = prec = -1;
retry:
                switch (fmt[i])
                {
                case ' ':
                    flags |= PFlag.SPACE;
                    i++;
                    goto retry;

                case '#':
                    flags |= PFlag.SHARP;
                    i++;
                    goto retry;

                case '+':
                    flags |= PFlag.PLUS;
                    i++;
                    goto retry;

                case '-':
                    flags |= PFlag.MINUS;
                    i++;
                    goto retry;

                case '0':
                    flags |= PFlag.ZERO;
                    i++;
                    goto retry;

                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                    n = 0;
                    for (; i < fmt.Length && Char.IsDigit(fmt[i]); i++)
                    {
                        n = 10 * n + (int)Char.GetNumericValue(fmt[i]);
                    }
                    if (i >= fmt.Length)
                    {
                        throw new ArgumentException("malformed format string - %%[0-9]");
                    }
                    if (fmt[i] == '$')
                    {
                        nextarg = n;
                        i++;
                        goto retry;
                    }
                    width  = n;
                    flags |= PFlag.WIDTH;
                    goto retry;

                case '*':
                    if ((flags & PFlag.WIDTH) != 0)
                    {
                        throw new ArgumentException("width given twice");
                    }
                    flags |= PFlag.WIDTH;
                    width  = getaster(fmt, ref i, ref nextarg, args);
                    if (width < 0)
                    {
                        flags |= PFlag.MINUS;
                        width  = -width;
                    }
                    i++;
                    goto retry;

                case '.':
                    if ((flags & PFlag.PREC) != 0)
                    {
                        throw new ArgumentException("precision given twice");
                    }
                    flags |= PFlag.PREC;
                    prec   = 0;
                    i++;
                    if (fmt[i] == '*')
                    {
                        prec = getaster(fmt, ref i, ref nextarg, args);
                        if (prec < 0)          /* ignore negative precision */
                        {
                            flags &= ~PFlag.PREC;
                        }
                        i++;
                        goto retry;
                    }
                    for (; i < fmt.Length && Char.IsDigit(fmt[i]); i++)
                    {
                        prec = 10 * prec + (int)Char.GetNumericValue(fmt[i]);
                    }
                    if (i >= fmt.Length)
                    {
                        throw new ArgumentException("malformed format string - %%.[0-9]");
                    }
                    goto retry;

                case '\n':
                    i--;
                    goto case '%';

                case '\0':
                case '%':
                    if (flags != PFlag.NONE)
                    {
                        throw new ArgumentException("illegal format character - %%");
                    }
                    result += '%';
                    break;

                case 'c': {
                    object val;
                    nextarg = getarg(args, nextarg, out val);
                    if ((flags & PFlag.MINUS) == 0)
                    {
                        if (width > 0)
                        {
                            result = result.PadRight(result.Length + width);
                        }
                    }
                    char c = (char)Convert.ToInt32(val);
                    result += c;
                    result  = result.PadRight(result.Length + width);
                    break;
                }

                case 's': {
                    object arg;
                    nextarg = getarg(args, nextarg, out arg);
                    RString rs = RString.AsRString(ruby, arg);
                    if (rs.IsTainted)
                    {
                        tainted = true;
                    }
                    int len = rs.Length;
                    if ((flags & PFlag.PREC) != 0)
                    {
                        if (prec < len)
                        {
                            len = prec;
                        }
                    }
                    if ((flags & PFlag.WIDTH) != 0)
                    {
                        if (width > len)
                        {
                            width -= len;
                            if ((flags & PFlag.MINUS) == 0)
                            {
                                if (width > 0)
                                {
                                    result = result.PadRight(result.Length + width);
                                }
                            }
                            result += rs.ToString();
                            if ((flags & PFlag.MINUS) != 0)
                            {
                                if (width > 0)
                                {
                                    result = result.PadRight(result.Length + width);
                                }
                            }
                            break;
                        }
                    }
                    result += rs.ToString().Substring(0, len);
                    break;
                }

                case 'd':
                case 'i':
                case 'o':
                case 'x':
                case 'X':
                case 'b':
                case 'u': {
                    char   sc = '\0';
                    char   ch = fmt[i];
                    object val;
                    nextarg = getarg(args, nextarg, out val);
                    bool   sign   = false;
                    bool   bignum = false;
                    long   num    = 0;
                    string prefix = String.Empty;
                    string s      = String.Empty;
                    switch (ch)
                    {
                    case 'd':
                    case 'i':
                        sign = true; break;

                    case 'o':
                    case 'x':
                    case 'X':
                    case 'b':
                    case 'u':
                    default:
                        if ((flags & (PFlag.PLUS | PFlag.SPACE)) != 0)
                        {
                            sign = true;
                        }
                        break;
                    }
                    if ((flags & PFlag.SHARP) != 0)
                    {
                        if (fmt[i] == 'o')
                        {
                            prefix = "0";
                        }
                        else if (fmt[i] == 'x')
                        {
                            prefix = "0x";
                        }
                        else if (fmt[i] == 'X')
                        {
                            prefix = "0X";
                        }
                        else if (fmt[i] == 'b')
                        {
                            prefix = "0b";
                        }
                        if (prefix.Length > 0)
                        {
                            width -= prefix.Length;
                        }
                    }
bin_retry:
                    if (val is RFloat)
                    {
                        val = ((RFloat)val).ToInteger();
                        goto bin_retry;
                    }
                    else if (val is double)
                    {
                        val = RFloat.ToInteger(ruby, (double)val);
                        goto bin_retry;
                    }
                    else if (val is string)
                    {
                        val = RInteger.StringToInteger(ruby, (string)val, 0);
                        goto bin_retry;
                    }
                    else if (val is RString)
                    {
                        val = ((RString)val).ToInteger();
                        goto bin_retry;
                    }
                    else if (val is int)
                    {
                        num = (long)(int)val;
                    }
                    else if (val is long)
                    {
                        num = (long)val;
                    }
                    else if (val is uint)
                    {
                        num = (long)(uint)val;
                    }
                    else if (val is RBignum)
                    {
                        bignum = true;
                    }
                    else
                    {
                        num = RInteger.ToLong(ruby, val);
                    }
                    int bas = 0;
                    if (ch == 'u' || ch == 'd' || ch == 'i')
                    {
                        bas = 10;
                    }
                    else if (ch == 'x' || ch == 'X')
                    {
                        bas = 16;
                    }
                    else if (ch == 'o')
                    {
                        bas = 8;
                    }
                    else if (ch == 'b')
                    {
                        bas = 2;
                    }
                    if (!bignum)
                    {
                        if (sign)
                        {
                            if (ch == 'i')
                            {
                                ch = 'd';            /* %d and %i are identical */
                            }
                            if (num < 0)
                            {
                                num = -num;
                                sc  = '-';
                                width--;
                            }
                            else if ((flags & PFlag.PLUS) != 0)
                            {
                                sc = '+';
                                width--;
                            }
                            else if ((flags & PFlag.SPACE) != 0)
                            {
                                sc = ' ';
                                width--;
                            }
                            s = Convert.ToString(num, bas);
                            goto format_integer;
                        }
                        else
                        {
                            s = Convert.ToString(num, bas);
                            goto format_integer;
                        }
                    }
                    // bignum
                    RBignum big = (RBignum)val;
                    if (sign)
                    {
                        s = big.ToRString(bas).ToString();
                        if (s[0] == '-')
                        {
                            s  = s.Substring(1);
                            sc = '-';
                            width--;
                        }
                        else if ((flags & PFlag.PLUS) != 0)
                        {
                            sc = '+';
                            width--;
                        }
                        else if ((flags & PFlag.SPACE) != 0)
                        {
                            sc = ' ';
                            width--;
                        }
                        goto format_integer;
                    }
                    if (big.Sign == false)
                    {
                        big = (RBignum)big.Clone();
                        big.TwoComp();
                    }
                    s = big.ToRString(bas).ToString();
                    if (s[0] == '-')
                    {
                        s = remove_sign_bits(s.Substring(1), bas);
                        StringBuilder sb = new StringBuilder(s.Length + 3);
                        sb.Append("..");
                        switch (bas)
                        {
                        case 16:
                            if (s[0] != 'f')
                            {
                                sb.Append('f');
                            }
                            break;

                        case 8:
                            if (s[0] != '7')
                            {
                                sb.Append('7');
                            }
                            break;
                        }
                        sb.Append(s);
                        s = sb.ToString();
                    }

format_integer:
                    int pos = -1;
                    int len = s.Length;

                    if (ch == 'X')
                    {
                        s = s.ToUpper();
                    }
                    if (prec < len)
                    {
                        prec = len;
                    }
                    width -= prec;
                    if ((flags & (PFlag.ZERO | PFlag.MINUS)) == 0 && s[0] != '.')
                    {
                        if (width > 0)
                        {
                            s = s.PadLeft(s.Length + width);
                        }
                    }
                    if (sc != '\0')
                    {
                        result += sc;
                    }
                    if (prefix.Length > 0)
                    {
                        result += prefix;
                        if (pos != 0)
                        {
                            pos += prefix.Length;
                        }
                    }
                    if ((flags & PFlag.MINUS) == 0)
                    {
                        char c = ' ';

                        if (s[0] == '.')
                        {
                            c = '.';
                            if ((flags & PFlag.PREC) != 0 && prec > len)
                            {
                                pos = result.Length;
                            }
                            else
                            {
                                pos = result.Length + 2;
                            }
                        }
                        else if ((flags & PFlag.ZERO) != 0)
                        {
                            c = '0';
                        }
                        if (width > 0)
                        {
                            result = result.PadRight(result.Length + width, c);
                        }
                    }
                    if (len < prec)
                    {
                        if (width > 0)
                        {
                            result = result.PadRight(result.Length + (prec - len), (s[0] == '.'?'.':'0'));
                        }
                    }
                    result += s;
                    if (width > 0)
                    {
                        result = result.PadRight(result.Length + width);
                    }
                    break;
                }

                case 'f':
                case 'g':
                case 'G':
                case 'e':
                case 'E': {
                    object val;
                    nextarg = getarg(args, nextarg, out val);
                    double fval = 0.0;

                    if (val is RString || val is string)
                    {
                        fval = Convert.ToDouble(((RString)val).ToString());
                    }
                    else if (val is int || val is long || val is uint)
                    {
                        fval = Convert.ToDouble(val);
                    }
                    else if (val is RFloat)
                    {
                        fval = ((RFloat)val).Double;
                    }
                    else if (val is double)
                    {
                        fval = (double)val;
                    }

                    string buf;
                    if (fmt[i] != 'e' && fmt[i] != 'E')
                    {
                        buf = new String(fmt[i], 1);
                        if ((flags & PFlag.PREC) != 0)
                        {
                            buf += prec.ToString();
                        }
                    }
                    else
                    {
                        buf = "#";
                        if ((flags & PFlag.SHARP) != 0)
                        {
                            buf += ".0";
                        }
                        buf += fmt[i];
                        if ((flags & PFlag.PLUS) != 0)
                        {
                            buf += '+';
                        }
                        if ((flags & PFlag.PREC) != 0)
                        {
                            buf += new String('0', prec);
                        }
                        else
                        {
                            buf += '0';
                        }
                    }
                    buf = fval.ToString(buf);
                    if ((flags & PFlag.WIDTH) != 0)
                    {
                    }
                    result += buf;
                    break;
                }

                default:
                    throw new ArgumentException(String.Format("malformed format string - %{0}", fmt[i]));
                }
                flags = PFlag.NONE;
            }
            if (tainted)
            {
                return(new RString(ruby, result, true));
            }
            return(result);
        }
Пример #28
0
        private RBignum divrem(RBignum y, out RBignum mod)
        {
            mod = null;
            uint  dd;
            int   ny = y.len;
            int   nx = len;
            int   i;
            ulong t2;

            if (ny == 0 && y.digits[0] == 0)
            {
                throw new DivideByZeroException("divided by 0");
            }
            if (nx < ny || nx == ny && digits[nx - 1] < y.digits[ny - 1])
            {
                mod = this;
                return(new RBignum(ruby, (uint)0, true));
            }
            if (ny == 1)
            {
                dd = y.digits[0];
                RBignum z = (RBignum)Clone();
                i  = nx;
                t2 = 0;
                while (i-- != 0)
                {
                    t2          = (ulong)BIGUP(t2) + z.digits[i];
                    z.digits[i] = (uint)(t2 / dd);
                    t2         %= dd;
                }
                z.sign   = (sign == y.sign);
                mod      = Uint2Big(ruby, (uint)t2);
                mod.sign = sign;
                return(z);
            }

            uint[] zz = new uint[(nx == ny) ? nx + 2 : nx + 1];
            if (nx == ny)
            {
                zz[nx + 1] = 0;
            }
            while (y.digits[ny - 1] == 0)
            {
                ny--;
            }

            dd = 0;
            uint q = y.digits[ny - 1];
            int  j = 0;

            uint[] ys = y.digits;
            while ((q & ((uint)1 << (int)(BITSPERDIG - 1))) == 0)
            {
                q <<= 1;
                dd++;
            }
            if (dd != 0)
            {
                RBignum yy = (RBignum)y.Clone();
                j  = 0;
                t2 = 0;
                while (j < ny)
                {
                    t2            += ((ulong)y.digits[j]) << (int)dd;
                    yy.digits[j++] = BIGLO(t2);
                    t2             = BIGDN(t2);
                }
                ys = yy.digits;
                j  = 0;
                t2 = 0;
                while (j < nx)
                {
                    t2     += ((ulong)digits[j]) << (int)dd;
                    zz[j++] = BIGLO(t2);
                    t2      = BIGDN(t2);
                }
                zz[j] = (uint)t2;
            }
            else
            {
                zz[nx] = 0;
                j      = nx;
                while (j-- != 0)
                {
                    zz[j] = digits[j];
                }
            }

            j = (nx == ny) ? nx + 1 : nx;
            do
            {
                if (zz[j] == ys[ny - 1])
                {
                    q = (uint)(BIGRAD - 1);
                }
                else
                {
                    q = (uint)((BIGUP(zz[j]) + zz[j - 1]) / ys[ny - 1]);
                }
                if (q != 0)
                {
                    i = 0;
                    long num = 0;
                    t2 = 0;
                    do
                    {
                        t2 += (ulong)ys[i] * q;
                        ulong ee = (ulong)(num - BIGLO(t2));
                        num = (long)(zz[j - ny + i] + ee);
                        if (ee != 0)
                        {
                            zz[j - ny + i] = BIGLO(num);
                        }
                        num = BIGDN(num);
                        t2  = BIGDN(t2);
                    }while (++i < ny);
                    num += (long)(zz[j - ny + i] - t2);
                    while (num != 0)
                    {
                        i   = 0;
                        num = 0;
                        q--;
                        do
                        {
                            ulong ee = (ulong)(num + ys[i]);
                            num = (long)((ulong)zz[j - ny + i] + ee);
                            if (ee != 0)
                            {
                                zz[j - ny + i] = BIGLO(num);
                            }
                            num = BIGDN(num);
                        }while (++i < ny);
                        num--;
                    }
                }
                zz[j] = q;
            }while (--j >= ny);
            RBignum div = new RBignum(ruby, zz, sign == y.sign);

            mod = (RBignum)div.Clone();
            j   = (nx == ny ? nx + 2 : nx + 1) - ny;
            for (i = 0; i < j; i++)
            {
                div.digits[i] = div.digits[i + ny];
            }
            div.len = i;

            while (ny-- != 0 && mod.digits[ny] == 0)
            {
                ;
            }
            ny++;
            if (dd != 0)
            {
                t2 = 0;
                i  = ny;
                while (i-- != 0)
                {
                    t2            = (t2 | mod.digits[i]) >> (int)dd;
                    q             = mod.digits[i];
                    mod.digits[i] = BIGLO(t2);
                    t2            = BIGUP(q);
                }
                mod.len  = ny;
                mod.sign = sign;
            }
            return(div);
        }