We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

# Floating Point Problem

on
Medium Priority
339 Views
I have a C program that is running into problems rounding a float.  The calculation is as follows

//faceamt = 5000000 and rate = 205.07
premium = (faceamt / 1000) * rate;

//*******************************
void Round2Decimals(float *fn)
//********************************
{
long lrd;
double dg;
dg = ceil (*fn * 100);
if (dg - (double) *fn * 100 >= 0.51)
dg -= 1.0;
lrd = (long) dg;
*fn = (float) lrd / 100;
}

In the debugger, premium is calculated as 1.02535+e6 which appears to be correct.  This value is then passed to a function to round it to two decimals...
The problem is that dg ends up with 102535007 which is incorrect.  Where did the last two digits (07) come from and how can I avoid this without having to declare all variables as Doubles .
Thanks.

Upon further investigation...
I think the problem is typecasting a float to a double.
Example
float fltnum;
double dblnum;
fltnum = 205.07
dblnum = (double)fltnum;

//dblnum is now 205.07000732422.  This is what is causing the problems...
Comment
Watch Question

## View Solution Only

Commented:
Edited text of question
CERTIFIED EXPERT
Most Valuable Expert 2014
Top Expert 2015

Commented:
keep all amounts in cents instead of dollars

Commented:
Be careful that the multiplication by 100 doesn't overflow the lrd value.  1.02535e8 would cause a problem.

Commented:
One other thing, is premium defined as a pointer or a float?
If it is a float, then the line
is incorrect.  You would need

If it is a pointer, the line
premium = (faceamt / 1000) * rate;
is incorrect.  You would need
*premium = (faceamt / 1000) * rate;

Hope this helps

Commented:
Edited text of question

Commented:
Edited text of question

Commented:
If Possible Convert Float to Double.

This program works

#include <stdio.h>

#include <math.h>

//*******************************
void Round2Decimals(float *fn)
//********************************
{
long lrd;
double dg;
dg = ceil (*fn * 100);
if (dg - (double) *fn * 100 >= 0.51)
dg -= 1.0;
lrd = (long) dg;
*fn = (float) lrd / 100;
}

void main()
{
float faceamt;
float rate;

faceamt = (float)5000000;
rate = (float)205.07;
premium = (faceamt / 1000) * rate;
}

Commented:
As per my knowledge Float keeps only 7 digits intact, where as double keeps upto 15 digits. So you would be better off using double instead of float.

Commented:
Sorry but this did not work... in the debugger, premium has the value 1.02535+006 (which looks to be correct).  However, display this using a printf and the value is actually 1025350.0625.  This value is used when it is cast to a double (within the Round2Decimals() ).

Commented:
You need to convert all float to Double to get it working. Please try this ( after conversion)

I think, Float is not reliable after 7 digits.

#include <stdio.h>

#include <math.h>

//*******************************
void Round2Decimals(double *fn)
//********************************
{
long lrd;
double dg;
dg = ceil (*fn * 100);
if (dg - (double) *fn * 100 >= 0.51)
dg -= 1.0;
lrd = (long) dg;
*fn = (float) lrd / 100;
}

void main()
{
double faceamt;
double rate;

faceamt = (double)5000000.00;
rate = (double)205.07;
premium = (faceamt / 1000) * rate;
}

Commented:
YOU HAVE TO USE DOUBLE SINCE YOU NEED MORE THAN 7 DIGITS.
Have you checked that your debugger display the full result of your variable. It looks to me that it uses a exponential format and displays only 6 digits.

Commented:
Your code will be even faster if you use double, since all functions in math.h are are double functions and you don't need to convert float to double all the time.

Commented:
Thanks for the suggestion to convert variables to doubles but I already knew that would help.  I'm looking for a way to deal with this problem without having to convert to doubles (i.e. possibly a compiler option???).

Commented:
More points needed.

Commented:
I'll agree with ozo...it is best store all values as integers, then use a float for the result of the final calculation.

Commented:
May I suggest the excellent article 'what every computer scientist should know about
floating point arithmetic', by David Goldberg (March 1991 Computing Surveys).

It carefully explains (among other useful stuff) what's happening when rounding,
converting and chopping floating point mantissas (significands).

kind regards,

Jos aka jos@and.nl

Commented:
Why don't you want to use double?

Commented:
Any way. 50 points are not sufficient to my answer.
Sorry.

shayplace@hotmail.com

Commented:
Instead of saying what is not sufficient, why don't you name your price?  I presume that by making this statement, you have a correct and superior answer to all previous ones posted.

Commented:
why do you expect exact values (7 digits) when casting incompatible types (long, float, double) ??
See jos' comment.
Also keep in mind that casting depends on the compiler, includes and  processor type.

BTW,
fltnum = 205.07;
dblnum = (double)fltnum;
check fltnum, and you will see that it is 205.07000732422 too.

If you want to know what really happens, you need to print the value bit by bit, not using
any libc routine which reads a bunch of bits/bytes.
Also make shure that the variables are set to zero before using.
Commented:
Unlock this solution with a free trial preview.
(No credit card required)

Commented:
Oops.. error in my answer's sprintf statement.

* ___ *
Unlock the solution to this question.