Пример #1
0
        private static BcdNumber Add(BcdNumber f, BcdNumber s)
        {
            if (f._neg != s._neg)
            {
                if (s._neg)
                {
                    return(Sub(f, -s));
                }
                else
                {
                    return(Sub(s, -f));
                }
            }
            Align(ref f, ref s);
            var len    = Math.Max(f._len, s._len);
            var digits = new byte[len];

            SortSwap(ref f, ref s);
            SumDigits(f._digits, 0, s._digits, 0, ref digits, 0, out int pos);

            var result = new BcdNumber
            {
                _int    = f._int && s._int,
                _neg    = f._neg && s._neg,
                _digits = digits,
                _len    = digits.Length,
                _plen   = f._plen
            };

            return(result);
        }
Пример #2
0
        public static BcdNumber operator -(BcdNumber n)
        {
            var result = new BcdNumber(n);

            result._neg = !result._neg;
            return(result);
        }
Пример #3
0
 private static void SortSwap(ref BcdNumber f, ref BcdNumber s)
 {
     if (s._len > f._len)
     {
         var t = s;
         s = f;
         f = t;
     }
 }
Пример #4
0
 public BcdNumber(BcdNumber n)
 {
     _neg    = n._neg;
     _int    = n._int;
     _digits = new byte[n._len];
     Array.Copy(n._digits, _digits, n._len);
     _len  = n._len;
     _plen = n._plen;
 }
Пример #5
0
        private static BcdNumber Mul(BcdNumber f, BcdNumber s)
        {
            Align(ref f, ref s);
            var isInt = f._int && s._int;
            var neg   = f._neg != s._neg;
            var plen  = f._plen + s._plen;

            SortSwap(ref f, ref s);
            var cached   = new Dictionary <byte, MulByteCacheEntry>();
            var sumArray = new Queue <byte[]>();

            for (var i = 0; i < s._len; ++i)
            {
                var    mul = s._digits[i];
                byte[] r;
                if (cached.TryGetValue(mul, out MulByteCacheEntry fromCache))
                {
                    r = new byte[fromCache.Len + i];
                    Array.Copy(fromCache.Data, fromCache.Offset, r, i, fromCache.Len);
                    sumArray.Enqueue(r);
                }
                else
                {
                    var k       = i;
                    var mulByte = MulByte(f._digits, mul, k);
                    cached.Add(mul, new MulByteCacheEntry()
                    {
                        Data = mulByte, Offset = k
                    });
                    sumArray.Enqueue(mulByte);
                }
            }

            cached.Clear();
            var result = SumQueue(sumArray);

            return(new BcdNumber()
            {
                _digits = result,
                _len = result.Length,
                _plen = plen,
                _neg = neg,
                _int = isInt
            }.Trim());
        }
Пример #6
0
        private BcdNumber ShiftLeft(int amount)
        {
            if (amount == 0)
            {
                return(this);
            }
            if (IsZero())
            {
                return(Zero);
            }
            var plen = _plen - amount;

            if (plen >= 0)
            {
                var result = new BcdNumber(this);
                result._plen = plen;
                result._int  = plen == 0;
                return(result.Trim());
            }
            amount -= _plen;
            var noZeroesLen = _len;

            while (_digits[noZeroesLen - 1] == 0 && _len > 1)
            {
                --noZeroesLen;
            }
            var nLen   = noZeroesLen + amount;
            var digits = new byte[nLen];

            Array.Copy(_digits, 0, digits, amount, noZeroesLen);
            return(new BcdNumber()
            {
                _digits = digits,
                _int = true,
                _plen = 0,
                _len = _len + amount,
                _neg = _neg
            });
        }
Пример #7
0
 static BcdNumber()
 {
     Zero = new BcdNumber("0");
     One  = new BcdNumber("1");
 }
Пример #8
0
        private static void Align(ref BcdNumber f, ref BcdNumber s)
        {
            if (f._plen == s._plen)
            {
                return;
            }

            bool      isInt1  = f._int;
            int       len1    = f._len;
            int       plen1   = f._plen;
            var       digits1 = new List <byte>(len1);
            BcdNumber result1 = null;

            bool      isInt2  = s._int;
            int       len2    = s._len;
            int       plen2   = s._plen;
            var       digits2 = new List <byte>(len2);
            BcdNumber result2 = null;

            if (f._plen > s._plen)
            {
                var c     = f._plen - s._plen;
                var zeros = Enumerable.Repeat <byte>(0, c);
                plen2 += c;
                len2  += c;
                isInt2 = false;
                digits2.AddRange(zeros);
                digits2.AddRange(s._digits);
                result1 = f;
            }
            else
            {
                var c     = s._plen - f._plen;
                var zeros = Enumerable.Repeat <byte>(0, c);
                plen1 += c;
                len1  += c;
                isInt1 = false;
                digits1.AddRange(zeros);
                digits1.AddRange(f._digits);
                result2 = s;
            }

            if (result1 == null)
            {
                result1 = new BcdNumber
                {
                    _digits = digits1.ToArray(),
                    _neg    = f._neg,
                    _int    = isInt1,
                    _len    = len1,
                    _plen   = plen1
                };
            }

            if (result2 == null)
            {
                result2 = new BcdNumber
                {
                    _digits = digits2.ToArray(),
                    _neg    = s._neg,
                    _int    = isInt2,
                    _len    = len2,
                    _plen   = plen2
                };
            }

            f = result1;
            s = result2;
        }
Пример #9
0
        private static BcdNumber Div(BcdNumber f, BcdNumber s)
        {
            if (s == Zero)
            {
                throw new DivideByZeroException();
            }
            var neg    = f._neg != s._neg;
            var plen   = 0;
            var digits = new byte[f._len];
            var dPos   = 0;

            var maxPLen = Math.Max(f._plen, s._plen);

            if (maxPLen > 0)
            {
                f = f.ShiftLeft(maxPLen);
                s = s.ShiftLeft(maxPLen);
            }

            do
            {
                var shiftFix = f._digits[f._len - 1] < s._digits[s._len - 1] ? 1 : 0;
                if (f > s)
                {
                    var shift = f._len - s._len - shiftFix;
                    s  <<= shift;
                    dPos = +shift;
                }
                else if (f < s)
                {
                    var shift = s._len - f._len + shiftFix;
                    f   <<= shift;
                    dPos -= shift;
                }
                if (dPos < 0)
                {
                    var l = -dPos;
                    Array.Resize(ref digits, digits.Length + l);
                    Array.Copy(digits, 0, digits, l, digits.Length - l);
                    for (var i = 0; i < l; ++i)
                    {
                        digits[i] = 0;
                    }
                    plen += l;
                    dPos  = 0;
                }
                if (digits.Length <= dPos)
                {
                    Array.Resize(ref digits, dPos + 1);
                }
                var r = 0;
                while (f >= s)
                {
                    f -= s;
                    ++r;
                }
                digits[dPos] = (byte)r;
            } while (!f.IsZero() && plen < MaxResolution);

            return(new BcdNumber()
            {
                _digits = digits,
                _len = digits.Length,
                _int = plen == 0,
                _neg = neg,
                _plen = plen
            }.Trim());
        }
Пример #10
0
        private static BcdNumber Sub(BcdNumber f, BcdNumber s)
        {
            if (f._neg != s._neg)
            {
                if (s._neg)
                {
                    return(Add(f, -s));
                }
                else
                {
                    return(-Add(-f, s));
                }
            }
            if (f._neg)
            {
                var t = -f;
                f = -s;
                s = t;
            }
            var neg = false;
            var cmp = Compare(f, s);

            if (cmp == 0)
            {
                return(Zero);
            }
            if (cmp < 0)
            {
                neg = true;
                var t = f;
                f = s;
                s = t;
            }
            Align(ref f, ref s);
            var digits = new byte[f._len];
            var carry  = 0;
            var i      = 0;

            for (; i < s._len; ++i)
            {
                var r = f._digits[i] - s._digits[i] - carry;
                if (r < 0)
                {
                    r    += 10;
                    carry = 1;
                }
                else
                {
                    carry = 0;
                }
                digits[i] = (byte)r;
            }
            for (; i < f._len; ++i)
            {
                var r = f._digits[i] - carry;
                if (r < 0)
                {
                    r += 10;
                }
                carry     = 0;
                digits[i] = (byte)r;
            }
            i = digits.Length - 1;
            while (i >= 0 && digits[i] == 0)
            {
                --i;
            }
            if (i != digits.Length - 1)
            {
                Array.Resize(ref digits, digits.Length - (digits.Length - i - 1));
            }

            return(new BcdNumber()
            {
                _digits = digits,
                _len = digits.Length,
                _int = f._int && s._int,
                _neg = neg,
                _plen = f._plen
            }.Trim());
        }
Пример #11
0
        public static int Compare(BcdNumber f, BcdNumber s)
        {
            if (ReferenceEquals(f, null))
            {
                return(-1);
            }
            if (ReferenceEquals(s, null))
            {
                return(1);
            }
            if (f._neg != s._neg)
            {
                return(f._neg ? -1 : 1);
            }
            var n       = f._neg;
            var fIntLen = f._len - f._plen;
            var sIntLen = s._len - s._plen;

            if (fIntLen != sIntLen)
            {
                if (n)
                {
                    return(fIntLen > sIntLen ? -1 : 1);
                }
                else
                {
                    return(fIntLen > sIntLen ? 1 : -1);
                }
            }
            var intLen = sIntLen;

            for (var i = intLen - 1; i >= 0; --i)
            {
                if (f._digits[i + f._plen] == s._digits[i + s._plen])
                {
                    continue;
                }
                if (n)
                {
                    return(f._digits[i + f._plen] > s._digits[i + s._plen] ? -1 : 1);
                }
                else
                {
                    return(f._digits[i + f._plen] > s._digits[i + s._plen] ? 1 : -1);
                }
            }
            // integer parts are the same
            var pLen = Math.Min(f._plen, s._plen);

            for (var i = pLen; i >= 0; --i)
            {
                if (f._digits[i] == s._digits[i])
                {
                    continue;
                }
                if (n)
                {
                    return(f._digits[i] == s._digits[i] ? -1 : 1);
                }
                else
                {
                    return(f._digits[i] == s._digits[i] ? 1 : -1);
                }
            }
            // shared plen frac parts are the same
            if (f._plen == s._plen)
            {
                return(0);
            }
            if (n)
            {
                return(f._plen > s._plen ? -1 : 1);
            }
            else
            {
                return(f._plen > s._plen ? 1 : -1);
            }
        }