I'm struggling with how to correctly round the result of a calculation (a double) in c++ to n decimal places. Upon trying the standard approach (multiplying the number by 10^n, using the 'round' function to get the nearest long integer, then dividing that result by 10^n and recasting as double, as explained here: http://en.wikipedia.org/wiki/Rounding), I find that it gives unexpected results when applied to the results of a calculation (whose answer I think I know, but apparently the computer disagrees). An example for n=2:
#include <iostream>
#include "math.h"
int main()
{
double x 177.95d; //original number
double y yr;
y = x*(1.0d-0.3d); //perform a calculation. Should be 124.565
yr = (double) round(y/.01)*0.01; //round up y for n=2
printf("rounded value of y = %.2f\n",yr); //prints out 124.56
}
To be clear, I know that all the numbers involved don't have an exact binary representation, but I wouldn't expect a double (which I take it on faith has approximately 15 decimal-digit accuracy) to have trouble approximating a number to within 5 significant (decimal) figures. As many programs round numbers in this fashion, I assume it's possible (right?) Even spreadsheets do this...
UPDATE: Apparently, I can get this to work by simply increasing the rounding accuracy. For example: yr = (double) round(y/.0001)*0.0001; seems to yield the correct results for numbers rounded to two decimal digits. However, I can't quite figure out the relationship between the decimal rounding digits (n) and the number of required zeroes in the rounding function (let's call it m).
UPDATE UPDATE: I think I've cracked it. To begin, I note that the output stream formatters for doubles already round up decimal representations to whatever format you request (eg. printf("%.2f\n",12.345) will produce the output 12.35). This means that a float or double whose decimal representation is to be rounded to the nth decimal place must first be converted to a representation whose (n+1)th decimal digit is correct. Now, assuming that the cumulative error (e) in the decimal representation of y is << 1.0E-(n+1) (Machine epsilon for 64-bit doubles is approximately 2.E-16), the only time the round function gives a bad result is when the (n+1)th digit of y is 5, but the decimal approximation gives an (n+1)th digit of 4 and the (n+2)th digit is >=5. In fact, in the example I give, the decimal approximation of y to 15 digits is 124.564999999999984 --just such a pathological case. The round function must simply account for these cases.
Thus, I conclude: The minimum value of the exponent, m required in the rounding function (double) round(y/1.0E-m)*1.0E-m that's guaranteed to always give acceptable results for doubles rounded to the nth decimal place is equal to two more than that: m=n+2. This explains the positive result in my first update...