Really Big Numbers

On occasion you may need to calculate really big floating point numbers and even a Decimal is not big enough. Some programming languages like Lisp can handle this no problem. Other languages like C# have no native way to do this. I've never needed such a data type in my work since the numbers I calculate are well within the limits of dotNet's Decimal. However I love a challenge and came up with something that can calculate numbers of arbitrary size with a floating point.

The Number class uses an array of Int32 with a base of 10,000. The decimal position is set in a separate variable of type Int32 and the sign is set in a variable typed with a custom enum. Both are added to the display value created in the ToString() override.


        private List<int> _Data = new List<int>();
        private static int DigitBase = 10000;
        private static int DigitBaseCeiling = DigitBase - 1;
        private static int DigitsPerWord = DigitBaseCeiling.ToString().Length;
        private int _dp = 0;
        private Sign _sign = Sign.Positive;

       /// <summary>
        /// Overload of ToString method.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string result = string.Empty;
            foreach (int i in this._Data)
            {
                result = i.ToString(new String('0',DigitsPerWord)) + result;
            }

            if (this._dp > 0)
            {
                //Add Decimal & Trim Trailing zeros
                result = result.Insert(result.Length - this._dp, ".");
                result = result.TrimEnd('0');
            }

            // Trim leading zeros
            if(result.IndexOf("0.")!=0)
                result = result.TrimStart('0');

            // Put a zero in front of decimal only number.
            if (result.IndexOf(".") == 0)
                result = "0" + result;

            if (this.Sign == Sign.Negative)
                result = "-" + result;

            // No blanks & no negative zeros
            if (result.Length == 0 || result == "-0" || result == "-")
                result = "0";

            return result;
        }


E is set to a constant value so it doesn't need to be calculated.

        
        /// <summary>
        /// Natuaral Log base to 100 decimal places.
        /// </summary>
        public Number E
        {
            get
            {
                return new Number("2.71828182845904523536028747135266249775724709369995957...elided");
            }
         }
        


It can get slow when squaring or routing certain large numbers. For this reason I limited the decimal to 300 digits without which irrational numbers like the square route of 2 would calculate till your memory ran out and then crash.

        
        private static int _decimalLimit= 10;
       public static int DecimalLimit
        {
            get
            {
                return _decimalLimit;
            }
            set
            {
                // Max decimals to be 300. We can't calculate to infinity.
                _decimalLimit = (value < 300) ? value : 300;
            }
        }

       

The class contains all the overrides of numeric operators: +, -, /, *, --, ++, ^
...as well as the logical operators: >, <, ==, !=, >=, <=

There are also various special math methods like Round, Pow & Root. These last two were the trickiest parts of the class since they can become endless loops. Therefore I supplied 2 versions of Root & Pow to give the option of calculating to the nth root or not. To see the full class click the link below.


View Code

No comments:

Post a Comment