problem with nan

J

John Smith

The exercise is to calculate the approximate area of a circle by the
"calculus method." That is, finding the area of rectangles nearly
filling the circle. I calculate the area of rectangles in 1/4 of the
circle and multiply by 4 to get the total area.

In the code below, if the value of nrect is used in the for loop, the
value of area goes to "nan" in the last couple of iterations. When there
are slightly fewer iterations than the value of nrect, the output is OK.
This behaviour is the same for smaller values of nrect.

I'm not sure I understand nan (I know it means not-a-number). It seems
to have something to do with non-representable numbers or domain/range
errors but reading the relavent section in Harbison & Steele didn't
entirely enlighten me. Can someone explain nan and its relation to the
problem with this code?


/* Calculate the area of a circle and the value of Pi
using the "calculus method." */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[])
{
double sinx, angle, nrect, ht;
double len, area, radius, newht;
int idx;

if(argc != 2)
{
fprintf(stderr, "enter the radius of a circle\n");
exit(EXIT_FAILURE);
}
area = 0.0;
radius = strtod(argv[1], NULL);
nrect = 1000.0;
ht = radius / nrect;
newht = ht;

//for(idx = 0; idx <= nrect; idx++) /* output is nan */
for(idx = 0; idx <= 997; idx++) /* output is OK */
{
sinx = newht / radius; /* sine=opp side/hypot */
angle = tan(asin(sinx)); /* angle=tangent of inverse sine */
len = newht / angle; /* len of adj side=opp side/angle */
area += (len * ht); /* add area of rectangle to total */
printf("area: %f rects: %d\n", area, idx); /* debug */
newht += ht; /* increment length of opp side */
}
area *= 4.0;

printf("\narea of circle with radius %.2f", radius);
printf(" is approx. %.2f\n", area);
printf("approx. value of Pi = %f\n", area / (radius * radius));

return 0;
}
 
T

tigervamp

John said:
The exercise is to calculate the approximate area of a circle by the
"calculus method." That is, finding the area of rectangles nearly
filling the circle. I calculate the area of rectangles in 1/4 of the
circle and multiply by 4 to get the total area.

In the code below, if the value of nrect is used in the for loop, the
value of area goes to "nan" in the last couple of iterations. When there
are slightly fewer iterations than the value of nrect, the output is OK.
This behaviour is the same for smaller values of nrect.

I'm not sure I understand nan (I know it means not-a-number). It seems
to have something to do with non-representable numbers or domain/range
errors but reading the relavent section in Harbison & Steele didn't
entirely enlighten me. Can someone explain nan and its relation to the
problem with this code?


/* Calculate the area of a circle and the value of Pi
using the "calculus method." */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[])
{
double sinx, angle, nrect, ht;
double len, area, radius, newht;
int idx;

if(argc != 2)
{
fprintf(stderr, "enter the radius of a circle\n");
exit(EXIT_FAILURE);
}
area = 0.0;
radius = strtod(argv[1], NULL);
nrect = 1000.0;
ht = radius / nrect;
newht = ht;

//for(idx = 0; idx <= nrect; idx++) /* output is nan */
for(idx = 0; idx <= 997; idx++) /* output is OK */
{
sinx = newht / radius; /* sine=opp side/hypot */
angle = tan(asin(sinx)); /* angle=tangent of inverse sine */
len = newht / angle; /* len of adj side=opp side/angle */
area += (len * ht); /* add area of rectangle to total */
printf("area: %f rects: %d\n", area, idx); /* debug */
newht += ht; /* increment length of opp side */
}
area *= 4.0;

printf("\narea of circle with radius %.2f", radius);
printf(" is approx. %.2f\n", area);
printf("approx. value of Pi = %f\n", area / (radius * radius));

return 0;
}

The problem here is that sinx eventually grows beyond the domain of the
values accepted by the asin function. The argument to asin must be
between -1 and 1, after 999 iterations (on my machine) the value of
sinx is just over 1 and asin returns NaN. The NaN is propagated across
every calculation which contains a NaN. The reason sinx goes above 1
is due to the natue of floating point, see FAQ question 14.1, the
Floating Point section of your C text, and possibly
http://en.wikipedia.org/wiki/Floating_point for more detail.

You can implement a check to determine if sinx > 1.0 and set it to 1.0
if it is. Since, when this happens, it will always be in the last
couple of cycles of your iteration (regardless of nrect) and your
accuracy won't improve any more, you might just want to break out of
the loop when sinx goes above 1.

Rob Gamble
 
C

Christian Bau

John Smith said:
The exercise is to calculate the approximate area of a circle by the
"calculus method." That is, finding the area of rectangles nearly
filling the circle. I calculate the area of rectangles in 1/4 of the
circle and multiply by 4 to get the total area.

In the code below, if the value of nrect is used in the for loop, the
value of area goes to "nan" in the last couple of iterations. When there
are slightly fewer iterations than the value of nrect, the output is OK.
This behaviour is the same for smaller values of nrect.

I'm not sure I understand nan (I know it means not-a-number). It seems
to have something to do with non-representable numbers or domain/range
errors but reading the relavent section in Harbison & Steele didn't
entirely enlighten me. Can someone explain nan and its relation to the
problem with this code?

Every floating point operation will give you a result that is quite
close to the mathematical correct result. If you use "1.0 / 10.0" you
will get a number close to one tenth. It might be a bit larger, or a bit
smaller.

If you add up 1.0 / 1000.0 one thousand times, then you get a result
that is relatively close to 1.0. It might be a bit smaller, it might be
a bit larger.

What is asin (x) if x is a tiny bit larger than 1.0?
 
F

Fred L. Kleinschmidt

John said:
The exercise is to calculate the approximate area of a circle by the
"calculus method." That is, finding the area of rectangles nearly
filling the circle. I calculate the area of rectangles in 1/4 of the
circle and multiply by 4 to get the total area.

In the code below, if the value of nrect is used in the for loop, the
value of area goes to "nan" in the last couple of iterations. When there
are slightly fewer iterations than the value of nrect, the output is OK.
This behaviour is the same for smaller values of nrect.

I'm not sure I understand nan (I know it means not-a-number). It seems
to have something to do with non-representable numbers or domain/range
errors but reading the relavent section in Harbison & Steele didn't
entirely enlighten me. Can someone explain nan and its relation to the
problem with this code?

/* Calculate the area of a circle and the value of Pi
using the "calculus method." */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[])
{
double sinx, angle, nrect, ht;
double len, area, radius, newht;
int idx;

if(argc != 2)
{
fprintf(stderr, "enter the radius of a circle\n");
exit(EXIT_FAILURE);
}
area = 0.0;
radius = strtod(argv[1], NULL);
nrect = 1000.0;
ht = radius / nrect;
newht = ht;

//for(idx = 0; idx <= nrect; idx++) /* output is nan */
for(idx = 0; idx <= 997; idx++) /* output is OK */
{
sinx = newht / radius; /* sine=opp side/hypot */
angle = tan(asin(sinx)); /* angle=tangent of inverse sine */
len = newht / angle; /* len of adj side=opp side/angle */
area += (len * ht); /* add area of rectangle to total */
printf("area: %f rects: %d\n", area, idx); /* debug */
newht += ht; /* increment length of opp side */
}
area *= 4.0;

printf("\narea of circle with radius %.2f", radius);
printf(" is approx. %.2f\n", area);
printf("approx. value of Pi = %f\n", area / (radius * radius));

return 0;
}

I won't make any comments about your algorithm. But think about what
happens when you get near your upper limit (1000) of your loop. What is
the tangent of 90 degrees?
 
J

John Smith

tigervamp said:
The problem here is that sinx eventually grows beyond the domain of the
values accepted by the asin function. The argument to asin must be
between -1 and 1, after 999 iterations (on my machine) the value of
sinx is just over 1 and asin returns NaN. The NaN is propagated across
every calculation which contains a NaN. The reason sinx goes above 1
is due to the natue of floating point, see FAQ question 14.1, the
Floating Point section of your C text, and possibly
http://en.wikipedia.org/wiki/Floating_point for more detail.

Excellent. Thank you.
You can implement a check to determine if sinx > 1.0 and set it to 1.0
if it is. Since, when this happens, it will always be in the last
couple of cycles of your iteration (regardless of nrect)

[OT] Why will it always happen in the last couple of iterations,
regardless of the value of nrect?
 
K

Keith Thompson

[OT] Why will it always happen in the last couple of iterations,
regardless of the value of nrect?

The value of newht iterates from 0.0 to radius (in increments of ht,
which is radius/nrect), so the value of sinx iterates from 0.0 to 1.0.
For example, with nrects==1000, the successive values of sinx are
approximately 0.000, 0.001, 0.002, ..., 0.998, 0.999, 1.000. But
since these are only approximate, sinx can exceed 1.000, causing
asin(sinx) to fail.

Incidentally, since nrect takes only integer values, it should be an
int, not a double.

Note that the area is the only thing that needs to be computed by
accumulating results from each iteration of the loop. Everything else
should be calculable from the value of the integer iteration variable,
which is likely to reduce errors and avoid the problem you're seeing.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top