Beispiel #1
0
 public eeListNode(eeObject obj, eeNumber index, eeListNode prev, eeListNode next)
 {
     this.obj   = obj;
     this.index = index;
     this.prev  = prev;
     this.next  = next;
 }
Beispiel #2
0
        private eeNumber IntegerDivision(eeNumber divisor, out eeNumber mod)
        {
            // base case
            if (this.AbsoluteValue() < divisor.AbsoluteValue())
            {
                mod = this;
                return(new eeNumber(0));
            }

            Queue <byte>    bytesQue = new Queue <byte>(this.bytes); // a queue of the dividend as bytes
            List <eeNumber> quotient = new List <eeNumber>();        // quotient

            eeNumber divPart = null;

            while (bytesQue.Count() > 0)
            {
                /* Grab the next digit from dividend */
                var asList   = divPart == null ? new List <byte>() : divPart.bytes.ToList();
                var nextByte = bytesQue.Dequeue();
                asList.Add(nextByte);

                /* Keep grabbing until we run out or need more */
                divPart = new eeNumber(asList);
                while (bytesQue.Count() != 0 && divPart < divisor)
                {
                    quotient.Add(new eeNumber(0));

                    asList.Add(bytesQue.Dequeue());
                    divPart = new eeNumber(asList);
                    divPart.TrimZeros();
                }

                divPart.TrimZeros();

                /* Divide it and append the division to the quotient */
                eeNumber q = new eeNumber(1); // number of times divisor fits into this divPart
                while (divisor * q <= divPart)
                {
                    q += ONE;
                }
                q -= ONE;

                quotient.Add(q); // keep track of quotient

                /* Figure out the remainder*/
                divPart = divPart - (divisor * q);
            }

            // remainder
            mod = divPart;

            var intergerQuotient = new eeNumber(quotient);

            intergerQuotient.TrimZeros();

            return(intergerQuotient);
        }
Beispiel #3
0
 public eeObject this[eeNumber key]
 {
     get // retrieve
     {
         return(null);
     }
     set // assign
     {
         return;
     }
 }
Beispiel #4
0
        // removes the denominator of this number and returns it
        private eeNumber PopDenominator()
        {
            // if not a fraction
            if (this.IsInt())
            {
                return(new eeNumber(1));
            }

            var den = this.denominator;

            this.denominator = null;
            return(den);
        }
Beispiel #5
0
        private static eeNumber FromBinary(bool[] bin)
        {
            var num = new eeNumber(0);

            for (int idx = 0; idx < bin.Length; idx++)
            {
                if (bin[idx])
                {
                    num += new eeNumber((ulong)Math.Pow(2, bin.Length - idx - 1));
                }
            }

            return(num);
        }
Beispiel #6
0
        // returns a copy of this eeNumber
        public eeNumber Copy()
        {
            var copy = new eeNumber(0);

            copy.negative = this.negative;
            copy.bytes    = (byte[])this.bytes.Clone();

            if (this.IsFrac())
            {
                copy.denominator       = new eeNumber(0);
                copy.denominator.bytes = (byte[])this.denominator.bytes.Clone();
            }

            return(copy);
        }
Beispiel #7
0
        public static eeNumber RShift(eeNumber num1, eeNumber num2)
        {
            if (num1.IsFrac() || num2.IsFrac())
            {
                throw new Exception("Cannot shift a non-int or by a non-int");
            }

            List <bool> bin1 = num1.ToBinary();

            for (eeNumber i = ZERO.Copy(); i < num2; i += ONE)
            {
                bin1.RemoveAt(bin1.Count() - 1);
            }

            return(FromBinary(bin1.ToArray()));
        }
Beispiel #8
0
        public void Append(eeObject obj)
        {
            _count += eeNumber.ONE;
            if (LastNode == null) // if this is the second object to enter the list
            {
                var node = new eeListNode(obj.Copy(), _count.Copy(), HeadNode, null);
                LastNode      = node;
                HeadNode.next = node;
                return;
            }

            var newNode = new eeListNode(obj.Copy(), _count.Copy(), LastNode, null);

            this.LastNode.next = newNode;
            this.LastNode      = newNode;
        }
Beispiel #9
0
        /* https://stackoverflow.com/a/11419400/9628054 */
        public static eeNumber Power(eeNumber base_, eeNumber exp)
        {
            var y = ONE.Copy();

            while (true)
            {
                if ((exp & ONE) != ZERO)
                {
                    y *= base_;
                }
                exp >>= 1;
                if (exp == ZERO)
                {
                    return(y);
                }
                base_ *= base_;
            }
        }
Beispiel #10
0
        // Greatest Common Factor using Euclid's algorithm
        public eeNumber GCF(eeNumber prod2_orig)
        {
            var prod1 = this.Copy().AbsoluteValue();
            var prod2 = prod2_orig.Copy().AbsoluteValue();

            while (prod1 != ZERO && prod2 != ZERO)
            {
                if (prod1 > prod2)
                {
                    prod1 %= prod2;
                }
                else
                {
                    prod2 %= prod1;
                }
            }

            return(prod1 | prod2);
        }
Beispiel #11
0
        private string ApproximateDivision(long accurateTo)
        {
            if (this.denominator == null)
            {
                throw new Exception("Cannot approximate division on an integer");
            }

            eeNumber denom = this.PopDenominator(),
                     remainder,
                     integerQuotient = this.IntegerDivision(denom, out remainder);

            string approx = integerQuotient.NumeratorToString();

            if (remainder == ZERO)
            {
                return(approx);
            }

            const string ZEROSTR     = "0";
            string       decimalAprx = "";

            // If the dividend is longer than the max accuracy, iterate to that, otherwise, to max accuracy
            long c = denom.bytes.LongCount();

            if (c > accurateTo)
            {
                accurateTo += c;
            }

            for (int i = 1; i <= accurateTo; i++)
            {
                eeNumber dec = new eeNumber(
                    remainder.NumeratorToString() + ZEROSTR
                    );
                decimalAprx += dec.IntegerDivision(denom, out eeNumber rem).NumeratorToString();
                remainder    = rem;
            }
            decimalAprx = decimalAprx.TrimEnd('0');

            this.denominator = denom;

            return($"{approx}.{decimalAprx}");
        }
Beispiel #12
0
        public eeNumber Factorial()
        {
            if (this < ZERO)
            {
                throw new Exception();
            }
            else if (this == ZERO)
            {
                return(ONE.Copy());
            }

            var sum = ONE.Copy();

            for (eeNumber i = this.Copy(); i > ZERO; i -= ONE)
            {
                sum *= i;
            }

            return(sum);
        }
Beispiel #13
0
        public static eeNumber LShift(eeNumber num1, eeNumber num2)
        {
            if (num1.IsFrac() || num2.IsFrac())
            {
                throw new Exception("Cannot shift a non-int or by a non-int");
            }

            List <bool> bin1 = num1.ToBinary();

            // trim the tail
            //for (eeNumber i = ZERO.Copy(); i < num2; i += ONE)
            //    bin1.RemoveAt(bin1.Count() - 1);

            // add to the front
            for (eeNumber i = ZERO.Copy(); i < num2; i += ONE)
            {
                bin1.Add(false);
            }

            return(FromBinary(bin1.ToArray()));
        }
Beispiel #14
0
        /* Note:
         * We cannot use +, - (non-integer), or / operators in this function or it will cause an infinite recursion loop
         * We use the IntergerDivision function as a replacement for /
         */
        private void Simplify()
        {
            if (this.IsInt())
            {
                return;
            }

            var denom = PopDenominator();

            if (this == ZERO || denom == ONE) // if the numerator is zero or denom is 1, return as-is (without denom)
            {
                return;
            }

            // if the denominator is a power of 10, leave it as is, as it's easier to deal with.
            else if (denom.IsPowerOf10())
            {
                this.denominator = denom;
                return;
            }

            // use the GCF to simplify
            eeNumber gcf = this.GCF(denom);

            if (gcf == ONE) // no change needed
            {
                this.denominator = denom;
            }
            else
            {
                var newObj = this.IntegerDivision(gcf, out _);
                this.bytes = newObj.bytes;

                if (this.denominator != gcf) // if denom won't be 1
                {
                    this.denominator = denom.IntegerDivision(gcf, out _);
                }
            }
        }
Beispiel #15
0
        public eeNumber(string num)
        {
            if (num.StartsWith("-")) // If it's negative
            {
                negative = true;
                num      = num.Replace("-", "");
            }

            if (num.Contains('.'))          // if it's a decimal/double
            {
                var split = num.Split('.'); // seperate integer and decimal

                // set the denominator
                denominator = new eeNumber("1" + new string('0', split[1].Length));

                var fracNumerator = new eeNumber(split[1]);
                var intPart       = new eeNumber(split[0]);

                // continue for the numerator normally
                num = ((intPart * denominator) + fracNumerator).NumeratorToString();
            }

            bytes = num.ToCharArray().Select(x => byte.Parse(x.ToString())).ToArray();
        }
Beispiel #16
0
        // Warning: Subtraction will destroy the contents of num2 and set the contents of num1 to the result
        // Make sure to pass a copy of num2 if you are keeping its value
        public static eeNumber operator -(eeNumber num1_orig, eeNumber num2_orig)
        {
            eeNumber num1 = num1_orig.Copy(),
                     num2 = num2_orig.Copy();

            // If either number is a fraction, cross multiply
            if (num1.IsFrac() || num2.IsFrac())
            {
                eeNumber frac1 = num1.PopDenominator(),
                         frac2 = num2.PopDenominator();

                num1 *= frac2;
                num2 *= frac1;

                var ret = (num1 - num2) / (frac1 * frac2);

                ret.TrimZeros();
                ret.Simplify();

                return(ret);
            }

            // if the two nums are the same
            if (num1 == num2)
            {
                return(ZERO.Copy());
            }
            // if first num is negative
            else if (num1.negative && !num2.negative)
            {
                // add them then negate it
                num1.negative = false;
                var sum = num1 + num2;
                sum.negative = true;
                return(sum);
            }
            // if second num is negative
            else if (num2.negative && !num1.negative)
            {
                // minus and negatives cancel
                num2.negative = false;
                return(num1 + num2);
            }
            // If they're both negative
            else if (num1.negative && num2.negative)
            {
                // Treat this as adding a negative to a positive
                num2.negative = false;
                return(num1 + num2);
            }

            // If we're going to get a negative answer
            bool negate = false;

            if (num2 > num1)
            {
                // reverse the two
                var buf = num1;
                num1 = num2;
                num2 = buf;

                // and negate
                negate = true;
            }

            // Reverse because we're subtracting from right to left.
            byte[] l_bytes = num1.bytes.Reverse().ToArray(),
            r_bytes = num2.bytes.Reverse().ToArray();

            bool carry = false;
            int  i;

            for (i = 0; i < r_bytes.Length; i++)
            {
                // Account for the previous carry
                if (carry)
                {
                    r_bytes[i]++;
                    carry = false;
                }

                // Subtract the digits
                byte digitDiff;
                if (l_bytes[i] < r_bytes[i]) // account for carry
                {
                    digitDiff = (byte)((10 + l_bytes[i]) - r_bytes[i]);
                    carry     = true;
                }
                else
                {
                    digitDiff = (byte)(l_bytes[i] - r_bytes[i]);
                }

                // Set the digit
                l_bytes[i] = digitDiff;
            }


            // If there is still carry left
            while (carry)
            {
                // subtract one from the next value
                if (l_bytes[i] == 0)
                {
                    l_bytes[i] = 9;
                    i++;
                }
                else
                {
                    l_bytes[i] -= 1;
                    carry       = false;
                }
            }

            // Put it in order again
            l_bytes = l_bytes.Reverse().ToArray();

            num1.bytes    = l_bytes;
            num1.negative = negate;
            num1.TrimZeros();

            return(num1);
        }
Beispiel #17
0
        public static eeNumber operator +(eeNumber num1, eeNumber num2)
        {
            // If either number is a fraction, cross multiply
            if (num1.IsFrac() || num2.IsFrac())
            {
                eeNumber frac1 = num1.PopDenominator(),
                         frac2 = num2.PopDenominator();

                num1 *= frac2;
                num2 *= frac1;

                var ret = (num1 + num2) / (frac1 * frac2);

                ret.TrimZeros();
                ret.Simplify();

                return(ret);
            }

            bool negate = false;

            // if first num is negative
            if (num1.negative && !num2.negative)
            {
                num1.negative = false;
                return(num2 - num1.Copy());
            }
            // If 2nd num is negative
            else if (num2.negative && !num1.negative)
            {
                num2.negative = false;
                return(num1 - num2.Copy());
            }
            // They're both negative
            else if (num1.negative && num2.negative)
            {
                num1.negative = false;
                num2.negative = false;
                negate        = true;
            }

            if (num2.bytes.Length > num1.bytes.Length)
            {
                // switch so that num1 is larger
                var buf = num1;
                num1 = num2;
                num2 = buf;
            }

            // Reverse because we're adding from right to left.
            byte[] lhs = num1.bytes.Reverse().ToArray(),
            rhs = num2.bytes.Reverse().ToArray();

            int i;

            for (i = 0; i < rhs.Length; i++)
            {
                byte digitSum = (byte)(rhs[i] + lhs[i]);
                lhs[i] = digitSum;
            }

            num1.bytes = lhs.Reverse().ToArray();
            num1.CarryOver();
            num1.negative = negate;

            return(num1);
        }
Beispiel #18
0
        public static eeNumber operator *(eeNumber num1_orig, eeNumber num2_orig)
        {
            eeNumber num1 = num1_orig.Copy(),
                     num2 = num2_orig.Copy();

            // if either num is 0, return 0
            if (num1 == ZERO || num2 == ZERO)
            {
                return(new eeNumber(0));
            }

            bool negate = false;

            /* first account for negatives */
            // if either num is negative
            if (num1.negative ^ num2.negative)
            {
                // set both to non-negative to multiply them
                num1.negative = false;
                num2.negative = false;

                // apply negative afterwards
                negate = true;
            }
            else if (num1.negative && num2.negative)
            {
                // otherwise, negatives just cancel out
                num1.negative = false;
                num2.negative = false;
            }

            eeNumber final;

            // if only one num is a fraction
            if (num1.IsFrac() ^ num2.IsFrac())
            {
                eeNumber frac = num1.denominator != null ? num1 : num2,
                         reg  = num1.denominator != null ? num2 : num1;

                var den    = frac.PopDenominator();
                var newNum = (frac * reg) / den;

                final = newNum;
            }
            // if both nums are fractions
            else if (num1.IsFrac() && num2.IsFrac())
            {
                eeNumber frac1 = num1.PopDenominator(),
                         frac2 = num2.PopDenominator();

                final = (num1 * num2) / (frac1 * frac2);
            }
            // regular nums
            else
            {
                // Reverse because we're going from right to left.
                byte[] lhs = num1.bytes.Reverse().ToArray(),
                rhs = num2.bytes.Reverse().ToArray();

                // new digit
                eeNumber finalNum = new eeNumber(0);

                // foreach digit in on the top num
                for (int i = 0; i < rhs.Length; i++)
                {
                    byte        carry   = 0;
                    List <byte> product = new List <byte>();

                    // foreach digit in the bottom num
                    for (int j = 0; j < lhs.Length; j++)
                    {
                        // multiply them
                        byte digitProduct = (byte)(lhs[j] * rhs[i]);

                        if (carry != 0)
                        {
                            digitProduct += carry;
                            carry         = 0;
                        }

                        if (digitProduct > 9)
                        {
                            carry         = (byte)(digitProduct / 10);
                            digitProduct %= 10;
                        }

                        product.Add(digitProduct);
                    }

                    // If carry is left
                    if (carry != 0)
                    {
                        product.Add(carry);
                    }

                    product.Reverse();

                    // Add the needed amount of trailing zeros for place value
                    for (int z = 0; z < i; z++)
                    {
                        product.Add(0);
                    }

                    finalNum += new eeNumber(product.ToArray());
                }

                final = finalNum;
            }

            final.negative = negate;
            return(final);
        }
Beispiel #19
0
        public static eeNumber operator /(eeNumber num1_orig, eeNumber num2_orig)
        {
            /* eeNumbers do not perform traditional division. That is only done
             * when the number needs to be approximated for a text representation.
             * For divison, we always keep the fractional form for arbitrary accuracy.
             */

            eeNumber num1 = num1_orig.Copy(),
                     num2 = num2_orig.Copy();

            if (num2 == ZERO)
            {
                throw new DivisionByZeroError(num1);
            }

            bool negate = false;

            /* first, account for negatives */
            // if either num is negative
            if (num1.negative ^ num2.negative)
            {
                // set both to non-negative to multiply them
                num1.negative = false;
                num2.negative = false;

                // apply negative afterwards
                negate = true;
            }
            else if (num1.negative && num2.negative)
            {
                // otherwise, negatives just cancel out
                num1.negative = false;
                num2.negative = false;
            }

            /* then, divide */
            bool a = num1.IsFrac(), b = num2.IsFrac();

            // frac divided by num
            if (a && !b)
            {
                num1.denominator *= num2;
                num1.negative     = negate;
                num1.Simplify();

                return(num1);
            }
            // num divided by num
            else if (!a && !b)
            {
                // check if right is a factor of left
                if (num1 > num2)
                {
                    var m = num1 % num2;
                    if (m == ZERO)
                    {
                        return(num1 % num2);
                    }
                }

                num1.denominator = num2;
                num1.negative    = negate;
                num1.Simplify();

                return(num1);
            }
            // num divided by frac
            else if (!a && b)
            {
                eeNumber numerator   = num1 * num2.denominator;
                eeNumber denominator = num2;

                var newNum = numerator / denominator;
                newNum.negative = negate;
                return(newNum);
            }
            // frac divided by frac
            else
            {
                var denom1 = num1.PopDenominator();

                eeNumber numerator   = num1 * num2.PopDenominator();
                eeNumber denominator = num2 * denom1;

                var newNum = numerator / denominator;
                newNum.negative = negate;
                return(newNum);
            }
        }
Beispiel #20
0
        public static bool operator >(eeNumber num1, eeNumber num2)
        {
            bool flip = false;

            // if at least one number is a fraction
            if (num1.IsFrac() || num2.IsFrac())
            {
                eeNumber numerator1 = num1,
                         denom1     = num1.PopDenominator(),
                         numerator2 = num2,
                         denom2     = num2.PopDenominator();

                // cross multiply & compare
                return((numerator1 * denom2) > (numerator2 * denom1));
            }
            // lhs is neg and rhs isn't
            else if (num1.negative && !num2.negative)
            {
                return(false);
            }
            // lhs isn't neg and rhs is
            else if (!num1.negative && num2.negative)
            {
                return(true);
            }
            // both negative
            else if (num1.negative && num2.negative)
            {
                /* Copy the numbers, compare the positive ones in the inverse order.
                 * Simply flipping the comparison without altering the numbers creates an infinite loop
                 * and removing the negative from the original object could cause damage higher up.
                 */

                var num1_copy = num1.Copy();
                num1_copy.negative = false;

                var num2_copy = num2.Copy();
                num2_copy.negative = false;

                return(num2_copy > num1_copy);
            }

            // if both are whole numbers, compare digits normally.
            byte[] l_bytes = num1.bytes,
            r_bytes = num2.bytes;

            // If lhs has more digits
            if (l_bytes.Length > r_bytes.Length)
            {
                return(true);
            }
            // If rhs has more digits
            else if (l_bytes.Length < r_bytes.Length)
            {
                return(false);
            }
            else // if they have an equal number of digits
            {
                // iterate through each digit
                for (int i = 0; i < l_bytes.Length; i++)
                {
                    // If the lhs digit is greater, return true
                    if (l_bytes[i] > r_bytes[i])
                    {
                        return(true);
                    }
                    // If they're the same, move on to the next digit
                    else if (l_bytes[i] == r_bytes[i])
                    {
                        continue;
                    }
                    else // if lhs is smaller, return false
                    {
                        return(false);
                    }
                }
            }

            // they're equal
            return(false);
        }