Convert a double to a string containing rational and surd First off, code:

string FracSurd(double value)
{
    //A C# 7 local function
    double GCD(double a, double b)
    {
        while (b &gt; 0)
        {
            var rem = a % b;
            a = b;
            b = rem;
        }
        return a;
    }
    for (int i = 0; i &lt;= 1e6; i++)
    {
        var SubjectToTest = value / Math.Sqrt(i);
        for (var denom = 1.0; denom &lt;= 500; denom++)
        {
            var numer = Math.Round(SubjectToTest * denom);
            if (SubjectToTest - numer / denom == 0)
            {
                int Square = 1, a = i;
                for (int b = 2; a &gt; 1; b++)
                    if (a % b == 0)
                    {
                        int x = 0;
                        while (a % b == 0)
                        {
                            a /= b;
                            x++;
                        }
                        //Console.WriteLine("{0} is a prime factor {1} times!", b, x);
                        for (int j = 2; j &lt;= x; j += 2) Square *= b;
                    }
                var LCM = GCD(numer, denom);
                numer /= LCM;
                denom /= LCM;
                var Builder = new System.Text.StringBuilder(numer.ToString());
                Builder.Append(" / ").Append(denom).Append(" √");
                foreach (var Char in (i / Square).ToString())
                {
#if WINDOWS_UWP
                    Builder.Append("̅");
                    Builder.Append(Char);
#else
                    Builder.Append(Char);
                    Builder.Append("̅");
#endif
                }
                return Builder.ToString();
            }
        }
    }
    throw new ArithmeticException("Cannot find appropiate fraction and surd.");
}


The code contains a lot of loops. How can I increase its performance so I can expand its range of input?
This is not a good question because the objective is unrealistic. The code (or perhaps the problem statement) is also flawed since √1 is considered a surd, which - if I am not mistaken - is wrong. (A surd is an "irrational nth root of a positive integer (n > 1)", i.e. it has a non-recurring floating point representation.)

Here is why the objective needs sorting out

Reasonably performant algorithms exist to express floating point numbers as irrational numbers (all of which may be expressed as x / y * √1).  Here's an example (E&amp;OE):

static string Frac(double value)
{
  const double compareTolerance = 1.0E-12;
  bool isNegative = value &lt; 0;
  value = Math.Abs(value);

  long numerator = 1L;
  long denominator = 1L;
  double fraction = (double)numerator / denominator;

  while (Math.Abs(fraction - value) &gt; compareTolerance)
  {
    if (fraction &lt; value)
      numerator++;
    else
    {
      denominator++;
      numerator = (long)(value * denominator);
    }
    fraction = (double)numerator / denominator;
  }
  return $"{numerator} / {denominator} ~= {fraction}, error = {value - fraction}";
}


Given Console.WriteLine(Frac(2.0 / 3 * Math.Pow(7, 1.0/3)));

One gets 1238109 / 970847 ~= 1.27528745518089, error = 7.04103442217274E-13

Reducing the "tolerance" leads to finding bigger (numerator, denominator) pairs giving "increasingly accurate" rational equivalents (within the significant digit limit of the floating point type of course). Taking the floating point representation of any rational, multiplying (or dividing) by a (floating point approximation to a) surd, just gives another floating point number which can be (approximately) represented by a rational. Every floating point number therefore has virtually unlimited rational * surd representations, so you need to specify how you want to limit the search range and/or output possibilities.