4
\$\begingroup\$

I have now written a simple square root calculator using the division method:

static void Main(string[] args)
{
    double num, sqrt = 0;
    int currentDecimal = 0, decimalAccuracyLevel, intAccuracyLevel = 5;

    do
    {
        Console.Write("Enter your number: ");
    } while (!double.TryParse(Console.ReadLine(), out num));

    do
    {
        Console.Write("Enter the number of decimal points you wish to be accurate to: ");
    } while (!int.TryParse(Console.ReadLine(), out decimalAccuracyLevel) && decimalAccuracyLevel >= 0);

    while (0 < intAccuracyLevel)
    {
        double currentIncrement = Math.Pow(10, intAccuracyLevel);

        while (Math.Pow(sqrt + currentIncrement, 2) <= num)
        {
            sqrt += currentIncrement;
        }

        intAccuracyLevel--;
    }

    while (currentDecimal <= decimalAccuracyLevel)
    {
        double currentIncrement = (double)1 / Math.Pow(10, currentDecimal);

        while (Math.Pow(sqrt + currentIncrement, 2) <= num)
        {
            sqrt += currentIncrement;
        }

        currentDecimal++;
    }

    Console.WriteLine(sqrt);
}

Is there anything I should do to improve performance or accuracy?

\$\endgroup\$
  • 1
    \$\begingroup\$ What is your motivation for reinventing-the-wheel, and do you have a reason for picking this algorithm over, say, logarithms or Newton's Method? \$\endgroup\$ – 200_success Jan 28 '15 at 23:42
  • \$\begingroup\$ I haven't written a square root solver before and I thought I might as well try it. I chose this method because I had done it this way by hand in high school, so I already knew it. \$\endgroup\$ – Hosch250 Jan 28 '15 at 23:43
4
\$\begingroup\$

Declare your variables a near as possible to their usage.


Initializing multiple variables on a single line removes readability and can lead in some languages to unexpected results.


If you divide two numbers and one of the numbers is a double the result is not a integer division result, hence you don't need the cast to double.


Because you are reinventing the wheel, it would be appropriate to do the Pow() by your code, because otherwise you could simply use Math.Pow(num, 0.5).


You should name your variables better. The int currentDecimal variable is storing the current calculated decimal points, but it reads that it holds the current Decimal number. You should rename it to currentDecimalPoint or something more meaningful.


This is a small application, but you should nevertheless extract the reading of the user input and the calculation of the result to separate methods.

\$\endgroup\$
  • \$\begingroup\$ Initializing multiple variables on a single line doesn't "remove" readability, but it sure hurts it ;-) \$\endgroup\$ – janos Jan 29 '15 at 6:50
2
\$\begingroup\$

Iteratively dividing the currentIncrement should be faster than Math.Pow in the general case.


Handle out-of-domain values of the sqrt function.


Use an epsilon value to avoid infinite loops.


class Program
{
    /* Anything below epsilon is zero for us. A difference of epsilon is also considered to be zero. */
    private const double Epsilon = 1e-15;

    static void Main(string[] args)
    {
        double number;
        int significantDigits;

        /* Read parameters from console. */
        GetParameters(out number, out significantDigits);

        /* Handle imaginary numbers too. */
        bool isResultImaginary = number < 0;

        var result = Sqrt(Math.Abs(number), significantDigits);

        Console.WriteLine(isResultImaginary ? "{0}i" : "{0}", result);
    }

    private static double Sqrt(double num, int decimalAccuracyLevel)
    {
        double sqrt = 0;
        double increment = 1e5;

        /* Calculate the integral part of the result. */
        while (increment > 1)
        {
            while ((sqrt + increment) * (sqrt + increment) <= num)
            {
                sqrt += increment;
            }

            increment /= 10;
        }

        increment = 1e0;

        /* Calculate the fractional part of the result. */
        while (0 <= decimalAccuracyLevel
               && increment > Epsilon)
        {
            while ((sqrt + increment) * (sqrt + increment) <= num)
            {
                sqrt += increment;
            }

            decimalAccuracyLevel--;
            increment /= 10;
        }

        return sqrt;
    }

    private static void GetParameters(out double num, out int decimalAccuracyLevel)
    {
        do
        {
            Console.Write("Enter your number: ");
        } while (!double.TryParse(Console.ReadLine(), out num));

        do
        {
            Console.Write("Enter the number of decimal points you wish to be accurate to: ");
        } while (!int.TryParse(Console.ReadLine(), out decimalAccuracyLevel) && decimalAccuracyLevel >= 0);
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.