Specialty Forums
Security and Virus
General Hardware
CPUs/Overclocking
Networking
Digital Photo/Video
Office Software
PC Gaming
Console Gaming
Programming
Database
Web Development
Digital Home

General Forums
Windows XP
Windows Vista
Windows 95/98
Windows Me
Windows NT
Windows 2000
Win Server 2008
Win Server 2003
Windows 3.1
Linux
PDAs
BeOS
Novell Netware
OpenVMS
Solaris
Disk Op. System
Unix
Mac
OS/2

Drivers
Driver Scan
Driver Forum

Software
Automatic Updates

BIOS Updates

My Computing.Net

Solution Center

Free IT eBook

Howtos

Site Search

Message Find

RSS Feeds

Install Guides

Data Recovery

About

Home
Reply to Message Icon Go to Main Page Icon

Slight inaccuracy Rounding Problem

Original Message
Name: cool_andy
Date: December 11, 2007 at 02:44:01 Pacific
Subject: Slight inaccuracy Rounding Problem
OS: Windows XP
CPU/Ram: 512
Model/Manufacturer: Acer
Comment:
Ok I have implemented the following function to round figures ".5" up instead of down.
float Round_float(float value)
{
char roundtest[40];
char *position = roundtest;


value += 0.00500001;


sprintf(roundtest,"%lf",value);

while ( *position != 0 )
{
if ( *position == '.')
{
*(position + 3) = 0;
/*replace 3rd decimal place with null*/
break;
}

position++;
}

return atof(roundtest);

}

This returns a 2.d.p figure. To test it I have done the following:
float test = 11.5549999;

test = Round_float(test);
printf("test = %.2f\n",test);

The figure is 11.56 in error. It should have been 11.55.
However if the test variable was 1 decimal place less than above 11.554999 (6.d.p). The figure is rounded to 11.55 correctly.

In my program I have many net price percentage increases which at the moment appear to be correctly rounded. Although the scenario above is unlikely to occur, I am justing wonder how to solve the slight inaccuracy above (7.d.p or more).

I have also just realised that 11.549999 plus 0.00500001 becomes 11.56. So only 0.005 is needed to be added on in this scenario case?


Report Offensive Message For Removal


Response Number 1
Name: Razor2.3
Date: December 11, 2007 at 06:22:56 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
Welcome to the amazing world of binary math, where
cos(x) != cos(y) && x == y

Sometimes it makes me think COBOL had it right, with its base 10 math.

Report Offensive Follow Up For Removal

Response Number 2
Name: StuartS
Date: December 11, 2007 at 06:32:46 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
If you want to round up to 2 decimal points then just add .005 in all circumstances.

.5 will round up the nearest integer with the fraction discarded.
.05 to one decimal point with digits over one discarded.
.005 to two decimal points with digits over two discarded.
.0005 to three decimal points with digits over three discarded.

add infinitum.

Stuart


Report Offensive Follow Up For Removal

Response Number 3
Name: klint
Date: December 11, 2007 at 11:48:30 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
Your method of truncating the non-significant digits, by converting to a string and back again, is very compute-intensive. Better to multiply by 100, 1000, etc., then truncate to its integer part using a suitable run-time library function, and divide by 100 or 1000. Also, instead of adding .5 and truncating, why not use the round() function?

For full details of rounding, see

http://en.wikipedia.org/wiki/Rounding

Also, if you really get into the subject, read "What every computer scientist should know about floating-point arithmetic":

http://docs.sun.com/source/806-3568...
http://www.physics.ohio-state.edu/~...


Report Offensive Follow Up For Removal

Response Number 4
Name: cool_andy
Date: December 12, 2007 at 03:11:17 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
Ok, if I add on just 0.005 to 11.5549999 its becomes 11.560000.
I would expect it to become 11.5599999 before truncating.
Is this possibly because floating point figures have a limit of 6.d.p? "%f" always displays six decimal figures.

Also I do not have access to trunc() and round() in the math.h library. I am using C. Are they standard C++ library functions?
Alternatively it would be useful to know a different truncate programming method than removing the 3rd decimal place in the string as above.

Thanks for your help

Andrew


Report Offensive Follow Up For Removal

Response Number 5
Name: klint
Date: December 12, 2007 at 06:54:41 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
When you add 0.005 to 11.5549999, it does not become 11.56000. It just appears to, when you print it. Floating-point numbers are not represented the same way internally as they are when printed in base 10.

The "%f" format can display to any precision you like; just specify it. If you want 10 dp, use "%.10f" It only prints 6dp by default because it's unusual that you would want more than than in typical circumstances.

The trunc() and round() functions are part of the ISO Standard C 99 language. If you are using a Microsoft compiler, it's unlikely that they've implemented that standard yet; you are probably still using the ISO C 90 standard. You can round the number to 2 dp by using this expression:

(f + 0.005) - fmod(f + 0.005, 0.01)

Alternatively, and a little closer to the method I mentioned in my earlier post:

((long)(f * 100 + 0.5) / 100


Report Offensive Follow Up For Removal


Response Number 6
Name: cool_andy
Date: December 12, 2007 at 07:53:58 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
Ok after using both my string method and your method above.
I still get the answer 11.56 rounded from 11.5549999 incorrectly.
If I use printf to specify 7.d.p "%.7f"
it displays (after adding 0.005):
11.5600004.
For some reason that appears to be an error margin of 0.0000005 (7.d.p).
Simliarly if I use printf to specify 8.d.p "%.8f" it displays:
11.56000042 (error margin = 0.00000052)

I just trying to understand why these figures above are appearing using printf.
However I only consider this a minor issue, and you have helped me learned a little more about rounding.
Thanks again for your advice
Andrew



Report Offensive Follow Up For Removal

Response Number 7
Name: klint
Date: December 12, 2007 at 09:02:21 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
When I do:

fprintf("%12.8f", 11.5549999 + 0.005);

I get 11.55999990, as you would expect. You get 11.56 when you printf("%f",...) because that rounds the displayed value to 6dp.

I have no idea why you get 11.5600004. That's strange. Could it be that you are sprintf'ing to 6dp and then converting back to 7dp, thus losing significant figures?


Report Offensive Follow Up For Removal

Response Number 8
Name: StuartS
Date: December 12, 2007 at 09:10:26 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
You want it rounded up to 2 decimal points which is what you are getting.

You will never get it exact when you are up to eight decimal points because of the vagaries of floating point binary arithmetic. Small errors will always creep in and .00000052 is a very small error. A little over five millionth.

Stuart


Report Offensive Follow Up For Removal

Response Number 9
Name: cool_andy
Date: December 12, 2007 at 09:28:10 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
I think I understand the problem, I suspect this is because the way floating point numbers are handled in binary arithemtic as you mention above. I noticed the webpages Klint posted above "What every computer scientist should know about floating-point arithmetic". Those articles look pretty complicated and difficult to understand.

However I do have one query following klint's last reply.
printf("%12.8f", 11.5549999 + 0.005);
It prints - 11.554999990, correctly

But if a variable is used after adding:
valye = 11.5549999;
value += 0.005;
printf("%12.8f",value);
It prints 11.56000042

I presume that is the way printf is handling the floating point figure?


Report Offensive Follow Up For Removal

Response Number 10
Name: klint
Date: December 13, 2007 at 02:28:06 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
cool_andy,

>But if a variable is used after adding:
>valye = 11.5549999;
>value += 0.005;
>printf("%12.8f",value);
>It prints 11.56000042
>
>I presume that is the way printf is
>handling the floating point figure?

No, this seems to be losing some accuracy. Are you using float? That doesn't hold that many decimal places, try using double. These days, with processors' built-in ability to do 80-bit floating point arithmetic, there is not much point in using float, unless you have a huge array of them and you want to use less memory.


Report Offensive Follow Up For Removal

Response Number 11
Name: cool_andy
Date: December 13, 2007 at 08:02:11 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
Hi,
If I declare "value" as a double variable, I get the following (8.d.p):
11.56000031

Slightly less error margin than using a float figure.
It seems if any figure is over 6.d.p close to the half way point, very small errors always occur.
Despite this I am happy with the useful advice you have given me about rounding floating point figures.
Thanks for your time.

Andrew


Report Offensive Follow Up For Removal

Response Number 12
Name: klint
Date: December 13, 2007 at 08:34:12 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
Strange. Something's just not right.

Using Visual Studio 2003, when I run the following program (copy&paste exact verbatim copy):

#include <stdio.h>

int main()
{
double value = 11.5549999;
value += 0.005;
printf("%12.8f", value);
return 0;
}

... it prints 11.55999990, just as expected. Can you copy & paste your complete application and tell me what it prints, and I'll try with my compiler to see if there is a difference.


Report Offensive Follow Up For Removal

Response Number 13
Name: cool_andy
Date: December 13, 2007 at 09:25:48 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
Ok I have managed to solve the problem. I made a silly mistake by forgeting to change the actually declared variable which was still float. This float variable "value" was being passed into round_double(double value) function, thus still giving an error margin.

I have also discovered the string method I created, is still rounding to 11.56 incorrectly.
But the method you mentioned above returns 11.55 correctly from 11.55999990
(f + 0.005) - fmod(f + 0.005, 0.01)

fmod gets the remainder after 2.d.p, which is 0.0099999.
Therefore 11.5599990 - 0.0099999 = 11.55

That seems to have done trick, thank you very much. Mission accomplished :)
I just have to remember to use double variables instead of float especially when my program contains a lot of discounts and nett prices stored in a linked list.


Report Offensive Follow Up For Removal

Response Number 14
Name: cool_andy
Date: December 13, 2007 at 09:32:50 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
I have just realised my string method does work if I alter sprintf to specify 8.d.p:
sprintf(roundtest,"%.8f",value);

"%lf" is only limiting to 6.d.p


Report Offensive Follow Up For Removal

Response Number 15
Name: klint
Date: December 13, 2007 at 09:36:40 Pacific
Subject: Slight inaccuracy Rounding Problem
Reply: (edit)
If you are working with currency amounts, you may be better off using long int to represent cents (or pence, or whatever your minor unit is.) Integral types have exact representations, rather than being subject to the pitfalls of floating-point.

Report Offensive Follow Up For Removal



Use following form to reply to current message:

   Name: From My Computing.Net Settings
 E-Mail: From My Computing.Net Settings

Subject: Slight inaccuracy Rounding Problem

Comments:

 
  Homepage URL (*): 
Homepage Title (*): 
         Image URL: 
 


Data Recovery Software




acer 312T BIOS problem

K7 Turbo possible max fsb?

Pc anywher problem

WinFLP & OE/Outlook2003

Computer resets after a few minutes


The information on Computing.Net is the opinions of its users. Such opinions may not be accurate and they are to be used at your own risk. Computing.Net cannot verify the validity of the statements made on this site. Computing.Net and Computing.Net, LLC hereby disclaim all responsibility and liability for the content of Computing.Net and its accuracy.
PLEASE READ THE FULL DISCLAIMER AND LEGAL TERMS BY CLICKING HERE

All content ©1996-2007 Computing.Net, LLC