You are here:

C/Strange behaviour in Floating Poing Arithmetic

Advertisement


Question
Hi,

I came across some strange behaviour in dealing with floating point arithmetic in a C code. The code is given below.

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

double roundvalues1( double , double );
double roundvalues2( double , double );


void main(int argc, char *argv[])
{

       double v1=0.00,
              v2=0.00;


       v1 = 4749.70;
       v2 = 0.15;

       fprintf(stdout,"\n------------------------------------------------------------\n\n\n");

       fprintf(stdout,"1---Sending to roundvalues1---\n");
       fprintf(stdout,"\n1.Rounded Value for [%f X %f]is :[%f]\n",v1,v2,roundvalues1(v1,v2));
       fprintf(stdout,"1---End of roundvalues1---\n\n");

       fprintf(stdout,"1---Sending to roundvalues2---\n");
       fprintf(stdout,"\n1.Rounded Value for [%f X %f]is :[%f]\n",v1,v2,roundvalues2(v1,v2));
       fprintf(stdout,"1---End of roundvalues2---\n\n\n");


       fprintf(stdout,"------------------------------------------------------------\n\n\n");
       v1 = 712.455;
       v2 = 1;

       fprintf(stdout,"2---Sending to roundvalues1---\n");
       fprintf(stdout,"\n2.Rounded Value for [%f X %f]is :[%f]\n",v1,v2,roundvalues1(v1,v2));
       fprintf(stdout,"2---End of roundvalues1---\n\n");

       fprintf(stdout,"2---Sending to roundvalues2---\n");
       fprintf(stdout,"\n2.Rounded Value for [%f X %f]is :[%f]\n",v1,v2,roundvalues2(v1,v2));
       fprintf(stdout,"2---End of roundvalues2---\n");

       fprintf(stdout,"\n------------------------------------------------------------\n\n");
}

double roundvalues2( double val1, double val2)
{
       char   c_charge[80];
       double d_charge=0.00;
       long   l_charge=0;

       d_charge=(val1*val2);
       printf("\td_charge after d_charge=(val1*val2 ) is [%f]\n",d_charge);

       if ((d_charge-712.455)!=0)
       {
               printf("\t1.difference of d_charge-712.455 is [%f]\n",(d_charge-712.455));
               if(d_charge > 712.455)
                       printf("\t\td_charge > 712.455\n");
               else if(d_charge < 712.455)
                       printf("\t\td_charge < 712.455\n");

       }

       l_charge = d_charge*10000;
       printf("\t1_charge after l_charge = d_charge*10000.00 is [%ld]\n",l_charge);

       d_charge=0.00;
       d_charge = l_charge/10000.00;
       printf("\td_charge after d_charge = d_charge/10000.00 is [%f]\n",d_charge);


       if ((d_charge-712.455)!=0)
       {
               printf("\t2.difference of d_charge-712.455 is [%f]\n",(d_charge-712.455));
       }

       c_charge[0]='\0';
       sprintf(c_charge,"%.2f",d_charge);
       printf("\tc_charge after  sprintf is [%s]\n",c_charge);

       d_charge=atof(c_charge);
       printf("\td_charge after  d_charge=atof(c_charge) is [%f]\n",d_charge);

       return(d_charge);
}

double roundvalues1( double val1, double val2)
{
       char   c_charge[80];
       double d_charge=0.00;

       d_charge=val1*val2;
       printf("\td_charge after d_charge=(val1*val2 ) is [%f]\n",d_charge);


       sprintf(c_charge,"%.2f",d_charge);
       printf("\tc_charge after sprintf is [%s]\n",c_charge);

       d_charge=0.00;
       d_charge=atof(c_charge);
       printf("\td_charge after  d_charge=atof(c_charge) is [%f]\n",d_charge);

       return(d_charge);
}

And the output is given below.

------------------------------------------------------------


1---Sending to roundvalues1---
       d_charge after d_charge=(val1*val2 ) is [712.455000]
       c_charge after sprintf is [712.45]
       d_charge after  d_charge=atof(c_charge) is [712.450000]

1.Rounded Value for [4749.700000 X 0.150000]is :[712.450000]
1---End of roundvalues1---

1---Sending to roundvalues2---
       d_charge after d_charge=(val1*val2 ) is [712.455000]
       1.difference of d_charge-712.455 is [-0.000000]
               d_charge < 712.455
       1_charge after l_charge = d_charge*10000.00 is [7124549]
       d_charge after d_charge = d_charge/10000.00 is [712.454900]
       2.difference of d_charge-712.455 is [-0.000100]
       c_charge after  sprintf is [712.45]
       d_charge after  d_charge=atof(c_charge) is [712.450000]

1.Rounded Value for [4749.700000 X 0.150000]is :[712.450000]
1---End of roundvalues2---


------------------------------------------------------------


2---Sending to roundvalues1---
       d_charge after d_charge=(val1*val2 ) is [712.455000]
       c_charge after sprintf is [712.46]
       d_charge after  d_charge=atof(c_charge) is [712.460000]

2.Rounded Value for [712.455000 X 1.000000]is :[712.460000]
2---End of roundvalues1---

2---Sending to roundvalues2---
       d_charge after d_charge=(val1*val2 ) is [712.455000]
       1_charge after l_charge = d_charge*10000.00 is [7124550]
       d_charge after d_charge = d_charge/10000.00 is [712.455000]
       c_charge after  sprintf is [712.46]
       d_charge after  d_charge=atof(c_charge) is [712.460000]

2.Rounded Value for [712.455000 X 1.000000]is :[712.460000]
2---End of roundvalues2---

------------------------------------------------------------

Basically what I'm trying to do is this. I have two double variables. I want to multiply these two and get the answer rounded to two decimal places. So here's where the roundvalues1 fucntion come in.
It basically multiplies the two incoming parameters and using an sprintf() formats it to a value with 2 decimal places and then converts back to a double and returns.

Now if you take the two sets of example values that I have taken;

4749.7 X 0.15 = 712.455
and
712.455 X 1   = 712.455

As you see in the output, after the sprintf();

4749.7 X 0.15 = 712.455  becomes 712.45
and
712.455 X 1   = 712.455  becomes 712.46

How can this behaviour be explained? And what is the solution for this? ( i mean to keep this consistant)

------------------------------------

In the roundvalues2 function I have taken a different approach. I've multiplied the the answer I get from multiplying the two parameters by 10000 to get rid of the decimal point and then divided it by 10000.00 and sent to sprintf().

In the meantime I've cheked whether the multiplied outcome of (4749.7 X 0.15) is equal to 712.455. Bu t as it appered to be it's not. And strangely enought it's less than 712.455.

Furthermore when the answer of this is multiplied by 10000 and assigned to a long variable the answer becomes 7124549. How can that be?

There it explains the rest of the senario. But how it became 7124549 is a mystry to me.

Can you please give an explernation tp this behaviour? And is there a way to rectify this?

I've tried this in Red hat linux Advanced Server and Red hat linux 7.1 using the gcc compiler. Also  I've tried this in Turbo C in Windows XP as well.

Appreciate a lot if you can get this clarified.

Thanks

Nivantha


Answer
The reason for this is, the way floating point number is represented inside your computer.
It is not represented the way you see on your screen.
It is represented in the way defined by IEEE standards.
It sets aside some part of the storage to mantissa, some part to exponent, etc.

If you want to truncate, you can use the trunc() or floor() functions.

-Narendra

C

All Answers


Answers by Expert:


Ask Experts

Volunteer


Narendra

Expertise

I can answer questions in C related to programming, data structures, pointers and file manipulation. I use Solaris for doing C code and if you have questions related to C programming on Solaris, I will be able to help better.

Experience

6.5

Organizations belong to
Sun Microsystems

Awards and Honors
Brain Bench Certified Expert C programmer.
Advanced System Software Certified

©2012 About.com, a part of The New York Times Company. All rights reserved.