Round float to X significant digits

Discussion in 'C++' started by David Corby, May 1, 2004.

  1. David Corby

    David Corby Guest

    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

    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, May 1, 2004
    #1
    1. Advertising

  2. David Corby

    David Corby Guest

    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
    >
    > 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!

    actual: somenumber = 2453126.72271099999

    should be

    actual: somenumber = 2453126.7227099999

    Note the 5th decimal place is a 0 instead of 1. Sorry for the mistake there.
    David Corby, May 1, 2004
    #2
    1. Advertising

  3. David Corby

    Karthik Guest

    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

    --
    Karthik
    Humans please 'removeme_' for my real email.
    Karthik, May 1, 2004
    #3
  4. David Corby

    Jon Bell Guest

    In article <hTGkc.131763$>,
    David Corby <> 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
    >> _exactly_ what I want instead of _about_ what I want.
    >>
    >> double somenumber = round(2453126.7227083333 * 100000.0) / 100000.0;
    >> desired: somenumber = 2453126.72271

    >
    >actual: somenumber = 2453126.7227099999


    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 <> Presbyterian College
    Dept. of Physics and Computer Science Clinton, South Carolina USA
    Jon Bell, May 1, 2004
    #4
  5. David Corby

    David Corby Guest

    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 :)
    David Corby, May 1, 2004
    #5
  6. David Corby <> wrote in message news:<hTGkc.131763$>...
    > 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.
    Bernhard Kick, May 1, 2004
    #6
  7. David Corby

    Bruce Guest

    In comp.lang.c++
    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
    >
    >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);
    }
    Bruce, May 1, 2004
    #7
  8. David Corby

    Julie Guest

    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
    >
    > 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.
    Julie, May 1, 2004
    #8
  9. David Corby

    Siemel Naran Guest

    "Bernhard Kick" <> wrote in message
    news:...

    > 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::precicsion(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.
    Siemel Naran, May 2, 2004
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. bd
    Replies:
    0
    Views:
    602
  2. Jason Lillywhite

    Increase significant digits in Float

    Jason Lillywhite, Mar 2, 2010, in forum: Ruby
    Replies:
    11
    Views:
    190
    Colin Bartlett
    Jul 1, 2010
  3. SMH
    Replies:
    0
    Views:
    213
  4. Roy Smith

    Significant digits in a float?

    Roy Smith, Apr 28, 2014, in forum: Python
    Replies:
    65
    Views:
    211
    Adam Funk
    May 8, 2014
  5. Ned Batchelder

    Re: Significant digits in a float?

    Ned Batchelder, Apr 28, 2014, in forum: Python
    Replies:
    2
    Views:
    47
    Ned Batchelder
    Apr 28, 2014
Loading...

Share This Page