public NetBigInteger[] DivideAndRemainder(
                NetBigInteger val)
            {
                if (val.m_sign == 0)
                    throw new ArithmeticException("Division by zero error");

                NetBigInteger[] biggies = new NetBigInteger[2];

                if (m_sign == 0)
                {
                    biggies[0] = Zero;
                    biggies[1] = Zero;
                }
                else if (val.QuickPow2Check()) // val is power of two
                {
                    int e = val.Abs().BitLength - 1;
                    NetBigInteger quotient = Abs().ShiftRight(e);
                    int[] remainder = LastNBits(e);

                    biggies[0] = val.m_sign == m_sign ? quotient : quotient.Negate();
                    biggies[1] = new NetBigInteger(m_sign, remainder, true);
                }
                else
                {
                    int[] remainder = (int[])m_magnitude.Clone();
                    int[] quotient = Divide(remainder, val.m_magnitude);

                    biggies[0] = new NetBigInteger(m_sign * val.m_sign, quotient, true);
                    biggies[1] = new NetBigInteger(m_sign, remainder, true);
                }

                return biggies;
            }
            public NetBigInteger Remainder(
                NetBigInteger n)
            {
                if (n.m_sign == 0)
                    throw new ArithmeticException("Division by zero error");

                if (m_sign == 0)
                    return Zero;

                // For small values, use fast remainder method
                if (n.m_magnitude.Length == 1)
                {
                    int val = n.m_magnitude[0];

                    if (val > 0)
                    {
                        if (val == 1)
                            return Zero;

                        int rem = Remainder(val);

                        return rem == 0
                            ? Zero
                            : new NetBigInteger(m_sign, new int[] { rem }, false);
                    }
                }

                if (CompareNoLeadingZeroes(0, m_magnitude, 0, n.m_magnitude) < 0)
                    return this;

                int[] result;
                if (n.QuickPow2Check())  // n is power of two
                {
                    result = LastNBits(n.Abs().BitLength - 1);
                }
                else
                {
                    result = (int[])m_magnitude.Clone();
                    result = Remainder(result, n.m_magnitude);
                }

                return new NetBigInteger(m_sign, result, true);
            }
            public NetBigInteger Divide(
                NetBigInteger val)
            {
                if (val.m_sign == 0)
                    throw new ArithmeticException("Division by zero error");

                if (m_sign == 0)
                    return Zero;

                if (val.QuickPow2Check()) // val is power of two
                {
                    NetBigInteger result = Abs().ShiftRight(val.Abs().BitLength - 1);
                    return val.m_sign == m_sign ? result : result.Negate();
                }

                int[] mag = (int[])m_magnitude.Clone();

                return new NetBigInteger(m_sign * val.m_sign, Divide(mag, val.m_magnitude), true);
            }
            public NetBigInteger Multiply(
                NetBigInteger val)
            {
                if (m_sign == 0 || val.m_sign == 0)
                    return Zero;

                if (val.QuickPow2Check()) // val is power of two
                {
                    NetBigInteger result = ShiftLeft(val.Abs().BitLength - 1);
                    return val.m_sign > 0 ? result : result.Negate();
                }

                if (QuickPow2Check()) // this is power of two
                {
                    NetBigInteger result = val.ShiftLeft(Abs().BitLength - 1);
                    return m_sign > 0 ? result : result.Negate();
                }

                int maxBitLength = BitLength + val.BitLength;
                int resLength = (maxBitLength + BitsPerInt - 1) / BitsPerInt;

                int[] res = new int[resLength];

                if (val == this)
                {
                    Square(res, m_magnitude);
                }
                else
                {
                    Multiply(res, m_magnitude, val.m_magnitude);
                }

                return new NetBigInteger(m_sign * val.m_sign, res, true);
            }