Velocity Reviews > C++ > Round float to X significant digits

# Round float to X significant digits

David Corby
Guest
Posts: n/a

 05-01-2004
Hi everybody, I've got a problem.

I'm trying to round a double to a particular number of significant
digits, in this case 5, but I can't figure out a way around getting
_exactly_ what I want instead of _about_ what I want. Taken down to just
the part relevant to my question, here's the code, the desired result,
and the actual result...

double somenumber = round(2453126.7227083333 * 100000.0) / 100000.0;

I've implemented this exact function in a other languages (Ruby, PHP)
and never run into this problem, so there's got to be SOME kind of
solution. Before I start ripping through Ruby's interpreter's source to
find out how they managed this, I was hoping that somebody who reads
this board has come up with a solution already.

Unfortunately, I need this number in floating-point, or at least I'll
need to be able to reliably convert it to floating-point. Any ideas?

David Corby
Guest
Posts: n/a

 05-01-2004
David Corby wrote:
> Hi everybody, I've got a problem.
>
> I'm trying to round a double to a particular number of significant
> digits, in this case 5, but I can't figure out a way around getting
> _exactly_ what I want instead of _about_ what I want. Taken down to just
> the part relevant to my question, here's the code, the desired result,
> and the actual result...
>
> double somenumber = round(2453126.7227083333 * 100000.0) / 100000.0;
>
> I've implemented this exact function in a other languages (Ruby, PHP)
> and never run into this problem, so there's got to be SOME kind of
> solution. Before I start ripping through Ruby's interpreter's source to
> find out how they managed this, I was hoping that somebody who reads
> this board has come up with a solution already.
>
> Unfortunately, I need this number in floating-point, or at least I'll
> need to be able to reliably convert it to floating-point. Any ideas?

Gaak!

should be

Note the 5th decimal place is a 0 instead of 1. Sorry for the mistake there.

Karthik
Guest
Posts: n/a

 05-01-2004
David Corby wrote:

> David Corby wrote:
>
>> Hi everybody, I've got a problem.
>>
>> I'm trying to round a double to a particular number of significant
>> digits, in this case 5, but I can't figure out a way around getting
>> _exactly_ what I want instead of _about_ what I want. Taken down to
>> just the part relevant to my question, here's the code, the desired
>> result, and the actual result...
>>
>> double somenumber = round(2453126.7227083333 * 100000.0) / 100000.0;

Not really sure if there is a function by name round in C++ .

#include <cmath>
#include <cstdio>
#include <cstdlib>

#define VAL 2453126.7227083333
#define HALF 0.5
#define GREATER_EQUAL_HALF(X) (X) >= HALF

double round(double val) {
long longval = (long)val;
if ( GREATER_EQUAL_HALF(val - longval) ) {
return ceil(val);
} else {
return floor(val);
}
}

int main() {
double somenumber = round(VAL * 100000.0) / 100000.0;
printf("\nValue %lf rounded to %lf", VAL, somenumber);
return EXIT_SUCCESS;
}

Having said that, implementation of double and int data types at the
hardware level are drastically different. Thatz why, you can be sure
that, 5 == 5 always returns true ( assuming, int here ) whereas ( 5.1
== 5.1 ) does not guarantee.
a small epsilon value (of your choice and tolerable limit, say 0.0000001).

HTH

--
Karthik
Humans please 'removeme_' for my real email.

Jon Bell
Guest
Posts: n/a

 05-01-2004
In article <hTGkc.131763\$(E-Mail Removed)>,
David Corby <(E-Mail Removed)> wrote:
>David Corby wrote:
>>
>> I'm trying to round a double to a particular number of significant
>> digits, in this case 5, but I can't figure out a way around getting
>>
>> double somenumber = round(2453126.7227083333 * 100000.0) / 100000.0;

>

It's impossible in floating-point binary, because of the fundamental
nature of floating-point binary representation. See FAQ [29.16] at
<http://www.parashift.com/c++-faq-lite/>.

--
Jon Bell <(E-Mail Removed)> Presbyterian College
Dept. of Physics and Computer Science Clinton, South Carolina USA

David Corby
Guest
Posts: n/a

 05-01-2004
Karthik wrote:
> David Corby wrote:
>
>> David Corby wrote:
>>
>>> Hi everybody, I've got a problem.
>>>
>>> I'm trying to round a double to a particular number of significant
>>> digits, in this case 5, but I can't figure out a way around getting
>>> _exactly_ what I want instead of _about_ what I want. Taken down to
>>> just the part relevant to my question, here's the code, the desired
>>> result, and the actual result...
>>>
>>> double somenumber = round(2453126.7227083333 * 100000.0) / 100000.0;

>
> Not really sure if there is a function by name round in C++ .
>
> #include <cmath>
> #include <cstdio>
> #include <cstdlib>
>
> #define VAL 2453126.7227083333
> #define HALF 0.5
> #define GREATER_EQUAL_HALF(X) (X) >= HALF
>
> double round(double val) {
> long longval = (long)val;
> if ( GREATER_EQUAL_HALF(val - longval) ) {
> return ceil(val);
> } else {
> return floor(val);
> }
> }
>
> int main() {
> double somenumber = round(VAL * 100000.0) / 100000.0;
> printf("\nValue %lf rounded to %lf", VAL, somenumber);
> return EXIT_SUCCESS;
> }
>
> Having said that, implementation of double and int data types at the
> hardware level are drastically different. Thatz why, you can be sure
> that, 5 == 5 always returns true ( assuming, int here ) whereas ( 5.1
> == 5.1 ) does not guarantee.
> When you talk about comparing double numbers, you always talk about a
> small epsilon value (of your choice and tolerable limit, say 0.0000001).
>
> HTH
>

Yes, it does help. Meh, I guess I'll just use a fixed decimal class.
Thanks for explaining the problem

Bernhard Kick
Guest
Posts: n/a

 05-01-2004
David Corby <(E-Mail Removed)> wrote in message news:<hTGkc.131763\$(E-Mail Removed)> ...
> David Corby wrote:
> > Hi everybody, I've got a problem.
> >
> > I'm trying to round a double to a particular number of significant
> > digits, in this case 5, but I can't figure out a way around getting
> > _exactly_ what I want instead of _about_ what I want. Taken down to just
> > the part relevant to my question, here's the code, the desired result,
> > and the actual result...
> >
> > double somenumber = round(2453126.7227083333 * 100000.0) / 100000.0;
> > desired: somenumber = 2453126.72271
> > actual: somenumber = 2453126.72271099999
> > [snip]

If you are only concerned about _printing_ the rounded number
(as opposed to round the number itsself)
you can use "classic C" printf():

#include <stdio.h>

int main() {
double x = 2453126.7227083333;

printf ("x=%f, round to 2,3,4,5 digits:\n %.2f %.3f %.4f %.5f\n",
x, x, x, x, x);
}

This prints:
x=2453126.722708, round to 2,3,4,5 digits:
2453126.72 2453126.723 2453126.7227 2453126.72271

(There is, i am sure, also a C++ way to do this,
i am not familiar enough with <iomanip>'s setw(), setprecision() etc...
Maybe some C++ expert can post an example?)

HTH,
Bernhard Kick.

Bruce
Guest
Posts: n/a

 05-01-2004
In comp.lang.c++
David Corby <(E-Mail Removed)> wrote:

>Hi everybody, I've got a problem.
>
>I'm trying to round a double to a particular number of significant
>digits, in this case 5, but I can't figure out a way around getting
>_exactly_ what I want instead of _about_ what I want. Taken down to just
>the part relevant to my question, here's the code, the desired result,
>and the actual result...
>
>double somenumber = round(2453126.7227083333 * 100000.0) / 100000.0;
>
>I've implemented this exact function in a other languages (Ruby, PHP)
>and never run into this problem, so there's got to be SOME kind of
>solution. Before I start ripping through Ruby's interpreter's source to
>find out how they managed this, I was hoping that somebody who reads
>this board has come up with a solution already.
>
>Unfortunately, I need this number in floating-point, or at least I'll
>need to be able to reliably convert it to floating-point. Any ideas?

from Snippets:

/* round number n to d decimal points */

inline double fround(double n, unsigned d)
{
return floor(n * pow(10., d) + .5) / pow(10., d);
}

Julie
Guest
Posts: n/a

 05-01-2004
David Corby wrote:
>
> Hi everybody, I've got a problem.
>
> I'm trying to round a double to a particular number of significant
> digits, in this case 5, but I can't figure out a way around getting
> _exactly_ what I want instead of _about_ what I want. Taken down to just
> the part relevant to my question, here's the code, the desired result,
> and the actual result...
>
> double somenumber = round(2453126.7227083333 * 100000.0) / 100000.0;
>
> I've implemented this exact function in a other languages (Ruby, PHP)
> and never run into this problem, so there's got to be SOME kind of
> solution. Before I start ripping through Ruby's interpreter's source to
> find out how they managed this, I was hoping that somebody who reads
> this board has come up with a solution already.
>
> Unfortunately, I need this number in floating-point, or at least I'll
> need to be able to reliably convert it to floating-point. Any ideas?

Do you need to *store* the result, or merely *display* the result?

Due to the way that floating point numbers are typically implemented, you
usually can't store an exact representation of all numbers, only approximations
as you have seen.

Siemel Naran
Guest
Posts: n/a

 05-02-2004
"Bernhard Kick" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...

> double x = 2453126.7227083333;
>
> printf ("x=%f, round to 2,3,4,5 digits:\n %.2f %.3f %.4f %.5f\n",
> x, x, x, x, x);
> }
>
> This prints:
> x=2453126.722708, round to 2,3,4,5 digits:
> 2453126.72 2453126.723 2453126.7227 2453126.72271
>
> (There is, i am sure, also a C++ way to do this,
> i am not familiar enough with <iomanip>'s setw(), setprecision() etc...
> Maybe some C++ expert can post an example?)

// std::cout << std::fixed; // optional
std::cout << std:recicsion(2) << x; // print 2453126.72

As for the getting the exact number in memory, it is generally impossible,
because 2.00008 may be represented internally in binary format, and will
display in decimal as 2.000079999999999999... Nevertheless, you can write
a general round function like

return std::floor(x*10000.0+0.5)/10000

But the use of division and floor may make the function slow, and better
solutions may be available.