Here’s the entire program

heron.c
#include <stdlib.h>
#include <stdio.h>

/* lower and upper iteration limits centered around 1.0 */
static double const eps1m01 = 1.0 - 0x1P-01;
static double const eps1p01 = 1.0 + 0x1P-01;
static double const eps1m24 = 1.0 - 0x1P-24;
static double const eps1p24 = 1.0 + 0x1P-24;

int main (int argc, char* argv[argc + 1]) {
    for (int i = 1; i < argc; ++i) {            // process args
        double const a = strtod(argv[i], 0);    // arg -> double
        double x = 1.0;
        for (;;) {                              // by powers of 2
            double prod = a * x;
            if (prod < eps1m01) {
                x *= 2.0;
            } else if (eps1p01 < prod) {
                x *= 0.5;
            } else {
                break;
            }
        }
        for (;;) {                              // Heron approximation
            double prod = a * x;
            if ((prod < eps1m24) || (eps1p24 < prod)) {
                x *= (2.0 - prod);
            } else {
                break;
            }
        }
        printf("heron: a=%.5e, \tx=%.5e, \ta*x=%.12f\n",
            a, x, a * x);
    }
    return EXIT_SUCCESS;
}

Here’s how it spits out the answer:

output
$ heron 0.07 5 6E+23
heron: a=7.00000e-02, 	x=1.42857e+01, 	a*x=0.999999999996
heron: a=5.00000e+00, 	x=2.00000e-01, 	a*x=0.999999999767
heron: a=6.00000e+23, 	x=1.66667e-24, 	a*x=0.999999997028

I’m not able to understand a few things, like for example:

  • why char* argv[argc + 1]? Why not char** argv[argc] or simply char** argv?
  • why the need for eps1m01, eps1p01, eps1m24 or eps1p24? What kind of optimization does it add to this program?