By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,851 Members | 1,109 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,851 IT Pros & Developers. It's quick & easy.

rounding function?

P: n/a
Is there a std lib rounding function that will round a real to a
given number of decimal places? Something like:

double round_it(double number, int decimal_digits)

pass 34.5678, 3 to it and it returns 34.568

Nov 14 '05 #1
Share this Question
Share on Google+
6 Replies


P: n/a
>Is there a std lib rounding function that will round a real to a
given number of decimal places? Something like:
No. Not in ANSI C.
double round_it(double number, int decimal_digits)

pass 34.5678, 3 to it and it returns 34.568


There is no exact representation of 34.568, or almost every other decimal
number, in binary floating point. Most implementations of floating
point use binary floating point, including the Intel x86 processors.

However, if you can tolerate the inaccuracy, try these:

#include <math.h>
#include <assert.h>
double round_to_integer(double value)
{
/* No, the case where value is negative is *NOT* a special case */
return floor(value+0.5);
}
double round_to_n_decimal_places(double value, int n)
{
int i;
double power_of_10;

assert(n >= 0);
/* calculate 10 ** N (FORTRAN expression) */
/* handling the case of n < 0 is left as an exercise */
for (n = 0, power_of_10 = 1.0; n > 0; n++) {
power_of_10 *= 10.0;
}
return round_to_integer(value * power_of_10)/power_of_10;
}

Note that I absolutely DON'T CARE what's done with the exactly-halfway-in-between
cases of, say, rounding 1.05 to 1 decimal place. The non-exact representation of
decimal fractions pretty much ensures that the exactly-halfway-in-between situation
will hardly ever occur. If you do care, you'll need to handle it specially.
There is also not much consensus about how the exactly-halfway-in-between case
SHOULD be handled, with the major camps being round up, round away from zero,
and round to even.

Gordon L. Burditt
Nov 14 '05 #2

P: n/a

"Curley Q." <cu*****@bogus.net> wrote
Is there a std lib rounding function that will round a real to a
given number of decimal places? Something like:

double round_it(double number, int decimal_digits)

pass 34.5678, 3 to it and it returns 34.568

I tried to write one a couple of years back, and posted it here. The general
consensus was that a good function (that rounds to the nearest decimal
representable by the precision of a double) was impossible to write in ANSI
C with any efficency.

The best way is to cheat

double round_it(double number, int decimal_digs)
{
char buff[128];

sprintf(buff, "%.*g", decimal_digs, number);
return strtod(buff);
}
Nov 14 '05 #3

P: n/a
Maybe this?
#include <math.h>
#include <stdio.h>

double roundit(double d,int dig)
{
long double m = powl(10,dig);
return roundl(d*m) / m;
}

int main(void)
{
double d = 1.123456789123456;

for (int i =1;i<15;i++) {
printf("[%3d] %20.15f\n",i,roundit(d,i));
}

}
This will output:
[ 1] 1.100000000000000
[ 2] 1.120000000000000
[ 3] 1.123000000000000
[ 4] 1.123500000000000
[ 5] 1.123460000000000
[ 6] 1.123457000000000
[ 7] 1.123456800000000
[ 8] 1.123456790000000
[ 9] 1.123456789000000
[ 10] 1.123456789100000
[ 11] 1.123456789120000
[ 12] 1.123456789123000
[ 13] 1.123456789123500
[ 14] 1.123456789123460
Nov 14 '05 #4

P: n/a
Curley Q. wrote:
Is there a std lib rounding function that will round a real to a given
number of decimal places? Something like:

double round_it(double number, int decimal_digits)

pass 34.5678, 3 to it and it returns 34.568


Here is my solution manipulating the double as a string:

/* round n to ndigits decimal digits */
char* round_it(char *n, int ndigits)
{
int int_digits, point;

for(int_digits = 0; point != '.'; ++int_digits)
point = n[int_digits];
if(n[int_digits + ndigits] >= '5')
++n[int_digits + (ndigits - 1)];

n[int_digits + ndigits] = '\0';

return n;
}

Nov 14 '05 #5

P: n/a

"Curley Q." <cu*****@bogus.net> a écrit dans le message de
news:40**************@bogus.net...
Curley Q. wrote:
Is there a std lib rounding function that will round a real to a given
number of decimal places? Something like:

double round_it(double number, int decimal_digits)

pass 34.5678, 3 to it and it returns 34.568


Here is my solution manipulating the double as a string:

/* round n to ndigits decimal digits */
char* round_it(char *n, int ndigits)
{
int int_digits, point;

for(int_digits = 0; point != '.'; ++int_digits)
point = n[int_digits];
if(n[int_digits + ndigits] >= '5')
++n[int_digits + (ndigits - 1)];

n[int_digits + ndigits] = '\0';

return n;
}


There are some problems with your solution.

Suppose you receive:
round("12.1",5);

You will index beyond the string you are getting
and touching memory you do not own. You assume that
there is a digit at the position of the point + "ndigits".

Another serious problem is that you just increase the
digit before the end alphabetically!!

If you had '9' you will get ':' as the result of your addition.
You do not carry over the digits. '9' should be transformed
into '0' and the same operation should be repeated until
there are no more digits in the whole string. This is called
"carry propagation".

In a more cosmetic way, you could use strchr to eliminate the
loop since you are just looking for a point. You do
char *p = strchr(n,'.');
if (p == NULL)
return n;
int_digits = p - n;

The termination clause of your "for" loop is just that the pointer
points to something different than the '.' char. If you receive
a string without a point you start an infinite loop since the terminating
zero will be ignored (it *is* different than '.') and you will go on
scanning beyond the end of the string with bad consequences:
either a crash or ending in a random fashion when you hit
some byte that has the value of '.'

Using strchr avoids that problem and is maybe faster. strchr
doesn't read beyond the end of the string, respecting the
terminating zero.

But for strings that contain a point, and have more
digits than the specified precision your function will
work. Of course if we do not hit the 9 in the previous
position. :-)

Nov 14 '05 #6

P: n/a
jacob navia wrote:
Jacob, thanks for your comments.
There are some problems with your solution.

Suppose you receive:
round("12.1",5);
The code I posted assumes validity of input.
You will index beyond the string you are getting
and touching memory you do not own. You assume that
there is a digit at the position of the point + "ndigits".
A full-fledged version would return the unmodified 1st argument
if the 2nd argument was >= the number of places available.

Another serious problem is that you just increase the
digit before the end alphabetically!!

If you had '9' you will get ':' as the result of your addition.
You do not carry over the digits. '9' should be transformed
into '0' and the same operation should be repeated until
there are no more digits in the whole string. This is called
"carry propagation".
Doh! Good call on this. That's what I get for posting code I
wrote in five minutes and tested twice. Back to the drawing board.
But for strings that contain a point, and have more
digits than the specified precision your function will
work. Of course if we do not hit the 9 in the previous
position. :-)


Nov 14 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.