Why Does the Compiler Print Negative Zero in This C Program?

  • Thread starter Thread starter STEMucator
  • Start date Start date
  • Tags Tags
    Compiler
AI Thread Summary
The discussion centers on a C program that calculates the sine and cosine of π/2 using Taylor series, resulting in unexpected outputs of negative and positive zero. The negative zero occurs due to the way floating-point arithmetic handles small values and rounding errors, particularly when using a limited number of terms in the series. Changing the number of terms in the cosine calculation alters the output to positive zero, highlighting the inexact nature of floating-point calculations. Participants emphasize the importance of understanding how the code functions rather than relying on assumptions about signed zeros. The conversation concludes with a focus on debugging and clarifying the behavior of the program rather than getting sidetracked by theoretical explanations.
STEMucator
Homework Helper
Messages
2,076
Reaction score
140

Homework Statement



This is not really a homework problem, but something is just so far off about this I had to ask. Note this is written in C.

Homework Equations


The Attempt at a Solution



Here's some simple code that computes values of ##\sin(x)## and ##\cos(x)## using their Taylor expansions. After six terms, the approximation exceeds the computer's ability to represent it:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

long double sinxSeries(int, double);
long double cosxSeries(int, double);

int factorial(int);

int main(){
    printf("sin(pi/2) = %Lf \n",sinxSeries(6, M_PI/2));
    printf("cos(pi/2) = %Lf \n",cosxSeries(6, M_PI/2));
    return 0;
}

long double sinxSeries(int n, double x) {
    long double returnSum = 0;
    
    for(int i=0;i<n;i++)
        returnSum += pow(-1,i) * (pow(x, 2*i + 1))/(factorial(2*i + 1));

    return returnSum;
}

long double cosxSeries(int n, double x) {
    long double returnSum = 0;
    
    for(int i=0;i<n;i++)
        returnSum += pow(-1,i) * (pow(x, 2*i))/(factorial(2*i));
    
    return returnSum;
}

int factorial(int n) {
    return(n <= 1 ? 1 : n*factorial(n-1));
}

This code produces the following output (note one of the outputs is horrendous):

Code:
sin(pi/2) = 1.000000 
cos(pi/2) = -0.000000 
Program ended with exit code: 0

Negative zero?

When I change this line:

Code:
printf("cos(pi/2) = %Lf \n",cosxSeries(6, M_PI/2));

To this:

Code:
printf("cos(pi/2) = %Lf \n",cosxSeries(7, M_PI/2));

I get positive zero:

Code:
sin(pi/2) = 1.000000 
cos(pi/2) = 0.000000 
Program ended with exit code: 0

What happened here exactly?
 
Last edited:
Physics news on Phys.org
I don't think you are getting exact positive and negative zeros here. Change the %Lf format to %Le, so you see what floating point values you are really calculating.

All calculation with float and double values are potentially inexact.
 
AlephZero said:
I don't think you are getting exact positive and negative zeros here. Change the %Lf format to %Le, so you see what floating point values you are really calculating.

All calculation with float and double values are potentially inexact.

I found some justification: http://en.wikipedia.org/wiki/Signed_zero

The value will never be completely accurate due to truncation and round off.
 
That integer factorial function is going to overflow as well. 13! doesn't fit in a 32 bit integer.

A more efficient way of calculating this is to compute the next term from the taylor polynomial from the previous.

You can more easily compute (-x^(n+2)) / (n+2)! from (x^n) / n! than from scratch.

Even better is http://mathworld.wolfram.com/HornersRule.html
 
Zondrina said:
I found some justification: http://en.wikipedia.org/wiki/Signed_zero
I suggest you stop trying to justify your statement about signed zeros with irrelevant links to wikipedia, and change the print format as I suggested.

The basic rule of debugging any computer software is to find out what the code actually does, not what you think it ought to do.
 
AlephZero said:
I suggest you stop trying to justify your statement about signed zeros with irrelevant links to wikipedia, and change the print format as I suggested.
The basic rule of debugging any computer software is to find out what the code actually does, not what you think it ought to do.
Yeah, i did that a long time ago. I already get it, like yesterday.

You don't seem to "get" my concern, but your hint to change the modifier was fine; even if it wasn't the point. It provided a visual, but not the answer. I was trying to understand the signed zero concept.

Thanks anyway.
 
Zondrina said:
You don't seem to "get" my concern, but your hint to change the modifier was fine; even if it wasn't the point.
AlephZero's hint was exactly to the point. Much of what you wrote in your opening post is incorrect. AlephZero was trying to point you toward a better understanding of the code that you wrote.


I was trying to understand the signed zero concept.
Your code does not exhibit the signed zero concept. It exhibits what happens to a number that is non-zero that prints as zero because of the output option you chose to use.
 

Similar threads

Replies
8
Views
2K
Replies
12
Views
2K
Replies
12
Views
2K
Replies
2
Views
2K
Replies
4
Views
1K
Replies
3
Views
1K
Replies
2
Views
3K
Replies
3
Views
1K
Back
Top