Ejemplo n.º 1
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;
        }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
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);
        }