Click here to Skip to main content
Click here to Skip to main content

Some handy decimal functions for double

, 20 Feb 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
Rounding, decimal places, etc..

Introduction

I use the functions in math.h a lot. But, some functions are missing, so I wrote my own. They are simple functions dealing with decimal places. Nothing big and fancy. But they can be handy sometimes.

Using the code

The functions are straightforward and self-explaining. These functions depend on math.h (and math.h only).

#include <span class="code-string">"math.h"</span>

Round() rounds a double to a certain number of decimal places. It is very similar to Excel's Round function.

// rounds a double variable to nPlaces decimal places
double Round(double dbVal, int nPlaces /* = 0 */)
{
    const double dbShift = pow(10.0, nPlaces);
    return  floor(dbVal * dbShift + 0.5) / dbShift; 
}

GetDecimalPlaces() counts and returns the number of decimal places of a double (refer to note 1).

// get the number of decimal places
int GetDecimalPlaces(double dbVal)
{
    static const int MAX_DP = 10;
    static const double THRES = pow(0.1, MAX_DP);
    if (dbVal == 0.0)
        return 0;
    int nDecimal = 0;
    while (dbVal - floor(dbVal) > THRES && nDecimal < MAX_DP)
    {
        dbVal *= 10.0;
        nDecimal++;
    }
    return nDecimal;
}

GetFmtStr() makes a printf()-style format string.

// get the number format string
const char* GetFmtStr(char* szFmt, int nDecimal)
{
    sprintf(szFmt, "%%.%dlf", nDecimal);
    return szFmt;
}

Finally, RoundUD() rounds up or rounds down a double to its nearest value in dbUnit steps.

// round up/down to certain units
double RoundUD(bool bRoundUp, double dbUnit, double dbVal)
{
    static const int ROUND_DP = 10;
    double dbValInUnit = dbVal / dbUnit;
    dbValInUnit = Round(dbValInUnit, ROUND_DP);
    if (bRoundUp) // round up
        dbValInUnit = ceil(dbValInUnit);
    else // round down
        dbValInUnit = floor(dbValInUnit);
    return (dbValInUnit * dbUnit);
}

You can test the functions above with the following code:

printf("rounding %lf d.p.=%d is %lf\n", 10.0,        1,    Round(10.0,         1));
printf("rounding %lf d.p.=%d is %lf\n", 0.0,         0,    Round(0.0,          1));
printf("rounding %lf d.p.=%d is %lf\n", 0.1,         1,    Round(0.1,          1));
printf("rounding %lf d.p.=%d is %lf\n", 0.01,        1,    Round(0.01,         1));
printf("rounding %lf d.p.=%d is %lf\n", 0.0123456,   0,    Round(0.0123456,    0));
printf("rounding %lf d.p.=%d is %lf\n", 0.0123456,   1,    Round(0.0123456,    1));
printf("rounding %lf d.p.=%d is %lf\n", 0.0123456,   2,    Round(0.0123456,    2));
printf("rounding %lf d.p.=%d is %lf\n", 0.0123456,   6,    Round(0.0123456,    6));
printf("rounding %lf d.p.=%d is %lf\n", -0.0123456,  6,    Round(-0.0123456,   6));
printf("rounding %lf up unit=%lf is %lf\n",   0.0,   0.05, RoundUD(true, 0.05, 0.0));
printf("rounding %lf down unit=%lf is %lf\n", 0.0,   0.05, RoundUD(false, 0.05, 0.0));
printf("rounding %lf up unit=%lf is %lf\n",   0.01,  0.05, RoundUD(true, 0.05, 0.01));
printf("rounding %lf down unit=%lf is %lf\n", 0.01,  0.05, RoundUD(false, 0.05, 0.01));
printf("rounding %lf up unit=%lf is %lf\n",   -0.01, 0.05, RoundUD(true, 0.05, -0.01));
printf("rounding %lf down unit=%lf is %lf\n", -0.01, 0.05, RoundUD(false, 0.05, -0.01));
printf("%lf has %d d.p.\n", 0.0,     GetDecimalPlaces(0.0));
printf("%lf has %d d.p.\n", 10.0,    GetDecimalPlaces(10.0));
printf("%lf has %d d.p.\n", -10.0,   GetDecimalPlaces(-10.0));
printf("%lf has %d d.p.\n", 10.123,  GetDecimalPlaces(10.123));
printf("%lf has %d d.p.\n", -10.123, GetDecimalPlaces(-10.123));
printf("%lf has %d d.p.\n", 10.01,   GetDecimalPlaces(10.01));
printf("%lf has %d d.p.\n", -10.01,  GetDecimalPlaces(-10.01));
char szFmt[32];
printf(GetFmtStr(szFmt, GetDecimalPlaces(0.0)), 0.0); printf("\n");
printf(GetFmtStr(szFmt, GetDecimalPlaces(10.0)), 10.0); printf("\n");
printf(GetFmtStr(szFmt, GetDecimalPlaces(10.010)), 10.010); printf("\n");
printf(GetFmtStr(szFmt, GetDecimalPlaces(-0.0345)), -0.0345); printf("\n");

The output will be something like:

rounding 10.000000 d.p.=1 is 10.000000
rounding 0.000000 d.p.=0 is 0.000000
rounding 0.100000 d.p.=1 is 0.100000
rounding 0.010000 d.p.=1 is 0.000000
rounding 0.012346 d.p.=0 is 0.000000
rounding 0.012346 d.p.=1 is 0.000000
rounding 0.012346 d.p.=2 is 0.010000
rounding 0.012346 d.p.=6 is 0.012346
rounding -0.012346 d.p.=6 is -0.012346
rounding 0.000000 up unit=0.050000 is 0.000000
rounding 0.000000 down unit=0.050000 is 0.000000
rounding 0.010000 up unit=0.050000 is 0.050000
rounding 0.010000 down unit=0.050000 is 0.000000
rounding -0.010000 up unit=0.050000 is 0.000000
rounding -0.010000 down unit=0.050000 is -0.050000
0.000000 has 0 d.p.
10.000000 has 0 d.p.
-10.000000 has 0 d.p.
10.123000 has 3 d.p.
-10.123000 has 3 d.p.
10.010000 has 2 d.p.
-10.010000 has 2 d.p.
0
10
10.01
-0.0345

Points of Interest

  • Note 1: GetDecimalPlaces() is worth some explanation. In a loop, the double is multiplied by 10 and then compared to its floor value (truncated value). If they are the same, it means we have exhausted the decimal places. Comparison between doubles is tricky because the internal representation of a double is not exact. So, the comparison must allow certain margins of error. The margin is specified by THRES, which is set to 1-10.

History

  • First version: 20 Feb 2008.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

S.C.Wong

Hong Kong Hong Kong
I don't know anything about Lisp, Ruby, D, EJB and J++.

Comments and Discussions

 
QuestionBug? PinmemberAvidFan28-Jun-12 2:01 
AnswerRe: Bug? PinmemberLarry Harding24-Jul-12 5:04 
GeneralFloating Point Explorer PinmemberMike O'Neill26-Feb-08 14:59 
GeneralRe: Floating Point Explorer PinmemberS.C.Wong27-Feb-08 16:06 
GeneralIncidentally ... PinmemberMike O'Neill27-Feb-08 16:48 
The download for your article is missing.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411028.1 | Last Updated 20 Feb 2008
Article Copyright 2008 by S.C.Wong
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid