nathanpjones / DecimalMath

The math support for Decimal that Microsoft forgot and more.
MIT License
47 stars 13 forks source link

Performance improvement for Sqrt #1

Closed Eric-Louchez closed 5 years ago

Eric-Louchez commented 8 years ago

Consider using Math.Sqrt(double) to produce an initial estimate of the square root. This improved performance 5x on my machine.

        /// <summary>
        /// Returns the square root of a given number. 
        /// </summary>
        /// <param name="s">A non-negative number.</param>
        /// <remarks> 
        /// Uses an implementation of the "Babylonian Method".
        /// See http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method 
        /// </remarks>
        public static decimal Sqrt(decimal s)
        {
            if (s < 0)
                throw new ArgumentException("Square root not defined for Decimal data type when less than zero!", "s");

            // Prevent divide-by-zero errors below. Dividing either
            // of the numbers below will yield a recurring 0 value
            // for halfS eventually converging on zero.
            if (s == 0 || s == SmallestNonZeroDec) return 0;

            var x = (decimal)Math.Sqrt((double)s);
            var halfS = s / 2m;
            var lastX = -1m;
            decimal nextX;

            while (true)
            {
                nextX = x / 2m + halfS / x;

                // The next check effectively sees if we've ran out of
                // precision for our data type.
                if (nextX == x || nextX == lastX) break;

                lastX = x;
                x = nextX;
            }

            return nextX;
        }
nathanpjones commented 8 years ago

That's a good point. And there may be some other ways to perform a faster starting approximation or even a better overall algorithm that converges more quickly. I'll look into it.