CS3343/3341
 Analysis of Algorithms 
Weird Topic
  Newton's Method for   
  Arbitrary Square Roots  


Square Root of an Arbitrary Double:

The program below incorporates normalization and calculates the square root of an arbitrary positive double.

For convenience the input double is given as a command line argument. In the several example outputs, there is one very small positive number and one very large one.

The output shown is from the Java program. The output from the C program differs only in trivial ways.

In the data below, black digits are correct, while red digits are incorrect.

Newton's Method, Square Root of the double r
Root.javaroot.c
// Root.java: use Newton's method for sqrt(r)
//  includes normalization.
public class Root {



   private double mul; // denormalizing factor

   // norm: normalize to 0.25 <= r <= 1.0
   public double norm(double r) {
      // divide d by even power of 2
      mul = 1.0; // power of 2
      double r0 = r;
      while (r0 > 1) {
         // divide by 4, will
         // later multiply by 2
         r0 = r0/4.0;
         mul = mul*2.0;
      }
      while (r0 < 0.25) {
         r0 = r0*4.0;
         mul = mul/2.0;
      }
      // r0 now normalized
      return r0;
   }

   // denorm: reverse the normalization
   public double denorm(double sqrtR0) {
      return sqrtR0*mul;
   }

   // calculate sqrt(r0), 0.25 <= d0 <= 1
   public double sqrt0(double r0) {
      // initial approx: x0 = (2/3)r0 + 0.3506
      double x0 = 0.66666*r0 + 0.3506;
      double x1;
      System.out.println(
         "1st approx to sqrt(r0): " + x0);
      for ( ; ; ) {
         x1 = x0/2.0 + r0/(2.0*x0);
         System.out.println(x1);
         if (Math.abs(x1 - x0) < 1.0e-7) break;
         x0 = x1;
      }
      return x1;   
   }

   public static void main(String[] args) {
      // calculate sqrt(r) for any r > 0
      Root root = new Root();
      double r = Double.parseDouble(args[0]);




      System.out.println("input is r: " + r +
         ", want sqrt(r)");
      // normalize to 0.25 <= r<= 1
      double r0 = root.norm(r);
      // r0 now normalized
      System.out.println("normalized is r0: " +
         r0 + ", want sqrt(r0)");
      double sqrtR0 = root.sqrt0(r0);
      // denoramlize: multiply sqrtR0 by mul
      double sqrtR = root.denorm(sqrtR0);
      System.out.println("sqrt(" + r + ") = " +
         sqrtR);
      System.out.println("check on ans: " +
         Math.sqrt(r));
   }
}
// root.c: use Newton's method for sqrt(r)
//  includes normalization.
#include <stdio.h>
#include <math.h>
#include<stdlib.h>

double mul; // denormalizing factor

// norm: normalize to 0.25 <= r <= 1.0
double norm(double r) {
   // divide d by even power of 2
   mul = 1.0; // power of 2
   double r0 = r;
   while (r0 > 1) {
      // divide by 4, will
      // later multiply by 2
      r0 = r0/4.0;
      mul = mul*2.0;
   }
   while (r0 < 0.25) {
      r0 = r0*4.0;
      mul = mul/2.0;
   }
   // r0 now normalized
   return r0;
}

// denorm: reverse the normalization
double denorm(double sqrtr0) {
   return sqrtr0*mul;
}

// calculate sqrt(r0), 0.25 <= d0 <= 1
double sqrt0(double r0) {
   // initial approx: x0 = (2/3)r0 + 0.3506
   double x0 = 0.66666*r0 + 0.3506;
   double x1;
   printf("1st approx to sqrt(r0): %18.16f\n",
      x0);
   for ( ; ; ) {
      x1 = x0/2.0 + r0/(2.0*x0);
      printf("%18.16f\n", x1);
      if (fabs(x1 - x0) < 1.0e-7) break;
      x0 = x1;
   }
   return x1;   
}

void main(int argc, char *argv[]) {
   // calculate sqrt(r) for any r > 0
   double r, r0, sqrtr0, sqrtr;
   if (argc != 2) {
      printf("Usage: \"./root 2\"\n");
      exit(1);
   }
   sscanf(argv[1], "%lf", &r);
   printf("input is r: %18.16f, want sqrt(r)\n",
      r);
   // normalize to 0.25 <= r<= 1
   r0 = norm(r);
   // r0 now normalized
   printf("normalized is r0: %18.16f", r0);
   printf(", want sqrt(r0)\n");
   sqrtr0 = sqrt0(r0);
   // denoramlize: multipy sqrtR0 by mul
   sqrtr = denorm(sqrtr0);
   printf("sqrt(%18.16f) = %18.16f\n",
      r, sqrtr);
   printf("check on ans: %18.16f\n", sqrt(r));
}


% javac Root.java
% java Root  2.0
input is r: 2.0, want sqrt(r)
normalized is r0: 0.5, want sqrt(r0)
1st approx to sqrt(r0): 0.68393
0.7074994845232699
0.7071068901731362
0.7071067811865559
0.7071067811865475
sqrt(2.0) = 1.414213562373095
check on ans: 1.4142135623730951

input is r: 1000.0, want sqrt(r) normalized is r0: 0.9765625, want sqrt(r0) 1st approx to sqrt(r0): 1.00163515625 0.9883017153911733 0.988211772895695 0.9882117688026186 sqrt(1000.0) = 31.622776601683796 check on ans: 31.622776601683793
% cc -o root -lm root.c
% ./root 10
input is r: 2.012E-7, want sqrt(r)
normalized is r0: 0.8438939648, want sqrt(r0)
1st approx to sqrt(r0): 0.913190350573568
0.918653257848627
0.9186370148561589
0.9186370147125578
sqrt(2.012E-7) = 4.485532298401161E-4
check on ans: 4.485532298401161E-4

input is r: 6.66E68, want sqrt(r) normalized is r0: 0.3859892650559098, ... 1st approx to sqrt(r0): 0.6079236034421729 0.6214270743888766 0.6212803606913861 0.6212803433683622 sqrt(6.66E68) = 2.580697580112789E34 check on ans: 2.580697580112788E34


Revision date: 2012-09-07. (Please use ISO 8601, the International Standard Date and Time Notation.)