Function to always round up to the nearest tenth

Pages: 12345
helios wrote:
The size of a function's stack frame is exactly dependent on the total sum of local data it allocates. main() could have the biggest stack frame of the program, or the smallest one.


Sure, that's just another type of SO - a recursive function with no base case.

TheideaMan wrote:
Anyway, all this is purely academic - probably not worth pursuing it any further.


https://en.wikipedia.org/wiki/Stack_overflow
Repeat:
The function main shall not be used within a program. - IS

One (of the many possible) reasons why ::main can't be used within a program is that the stack frame of ::main may contain synthesised RAII wrappers to destroy objects at namespace scope, invoke exit or quick_exit callbacks etc.
JLBorges, your solutions round off to the nearest figure. The original question was how to round up.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
unsigned long long ipow10( unsigned int p ) { return p == 0 ? 1 : 10 * ipow10(p-1) ; }

double round_nearest( double d, unsigned int prec )
{
    const auto pow = ipow10(prec) ;
    return std::round( d * pow ) / pow ;
}

double round_up( double d, unsigned int prec ) // up: towards positive infinity
{
    const auto pow = ipow10(prec) ;
    return std::ceil( d * pow ) / pow ;
}

double round_down( double d, unsigned int prec ) // down: towards negative infinity
{
    const auto pow = ipow10(prec) ;
    return std::floor( d * pow ) / pow ;
}

double round_towards_zero( double d, unsigned int prec )
{
    const auto pow = ipow10(prec) ;
    return std::trunc( d * pow ) / pow ;
}

double round_away_from_zero( double d, unsigned int prec )
{ return d < 0 ? round_down( d, prec ) : round_up( d, prec ) ; }

http://coliru.stacked-crooked.com/a/b2ed619f3f230600
Well, I need to clarify my question a little bit. I figured out what the variable "input_precision" was intended to be used for. From what I see, without feeding "input_precision" manually, the output by cout or stringstream will be truncated pretty considerately, and in some cases, making the round algorithm function incorrectly.

For example, if I input a double without feeding cout (input_precision) :
input : 30.8000001
output by cout : 30.8 // If the number is 30.8, it can't be rounded to 30.9!!


I think "input_precision" is actually the exact number of digits after a double's dot (.) I still cannot extract the way "input_precision" is calculated from the function random_d(). If I input a double manually, I still have to spend an extra second or two to specify "input_precision" for the input, so that I can get the round algorithm to work. I want a general-purpose function which can calculate "input_precision" for every double. I have done some research and tried implementing a function for myself, but failed :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// This function calculates the "input_precision" for every double
std::streamsize precision_d(double d)
{
    double d_part, i_part;
 
    std::streamsize d_precision = 0; 
    d_part = modf(d, &i_part);
   while(d_part)
    {
       d_precision += 1;  
       d_part *= 10.0;
       d_part = modf(d_part, &i_part);
    }
    return d_precision;
}


And the output :
d : 10041.5
rand_d() - prec : 1
prec_d() - prec : 1

d : 13243.465953
rand_d() - prec : 6
prec_d() - prec : 39 (Wrong!)

d : 4247.7
rand_d() - prec : 1
prec_d() - prec : 40 (Wrong!)

d : 13577.76859
rand_d() - prec : 5
prec_d() - prec : 37 (Wrong!)

d : 788
rand_d() - prec : 0
prec_d() - prec : 0

d : 10516.91952378
rand_d() - prec : 8
prec_d() - prec : 39 (Wrong!)

etc


Can someone help me with this function? Much very very appreciated.
@TheIdeasMan
Thanks for tidying the code for me. The code looks nice, I really appreciate it :)

But, will it be a good practice if I write code without "using namespace std;" starting from now?

Anyway, here is the test unit in case someone might be interested :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
    std::streamsize prec, input_precision = 0;

   std:: cout.setf(std:: ios::fixed);

    for(int test_cases = 10, N = 1; N <= test_cases; N++)
    {
        double d = random_d(prec); 
        input_precision = precision_d(d);

       std:: cout.precision(prec);
       
       std:: cout << "d : " << d << std:: endl;
        std:: cout << "rand_d() - prec : " << prec << std:: endl;
        std:: cout << "prec_d() - prec : " << input_precision << "\n\n";
    }
}
Last edited on
Thanks for tidying the code for me. The code looks nice, I really appreciate it :)


No worries, appreciate the thanks myself, although I really didn't do a lot :+) But you should really prefer JLBorges code - he is the master; I am just a back yard basher :+D

But, will it be a good practice if I write code without "using namespace std;" starting from now?


Yes, absolutely. Read up about the purpose of namespace, to see why. Ideally everyone should put their code into their own namespaces.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <cmath>
#include <iomanip>
#include <random>

// invariant: p < std::numeric_limits<unsigned long long>::digits10
unsigned long long ipow10( unsigned int p ) { return p == 0 ? 1 : 10 * ipow10(p-1) ; }

double round_nearest( double d, unsigned int prec )
{
    const auto pow = ipow10(prec) ;
    return std::round( d * pow ) / pow ;
}

double round_up( double d, unsigned int prec ) // up: towards positive infinity
{
    const auto pow = ipow10(prec) ;
    return std::ceil( d * pow ) / pow ;
}

double round_down( double d, unsigned int prec ) // down: towards negative infinity
{
    const auto pow = ipow10(prec) ;
    return std::floor( d * pow ) / pow ;
}

double round_towards_zero( double d, unsigned int prec )
{
    const auto pow = ipow10(prec) ;
    return std::trunc( d * pow ) / pow ;
}

double round_away_from_zero( double d, unsigned int prec )
{ return d < 0 ? round_down( d, prec ) : round_up( d, prec ) ; }

int main()
{
    std::cout << std::fixed << std::setprecision(10) << std::showpos ;

    for( double d : { 30.8000001, -30.8000001 } )
    {
        std::cout << "\n\n\nnumber: " << d
                  << "\n\nrounded to one digit after decimal point\n\n"
                  << "     towards nearest: " << round_nearest(d,1) << '\n'
                  << "towards +ve infinity: " << round_up(d,1) << '\n'
                  << "towards -ve infinity: " << round_down(d,1) << '\n'
                  << "        towards zero: " << round_towards_zero(d,1) << '\n'
                  << "      away from zero: " << round_away_from_zero(d,1) << '\n' ;
    }
}

number: +30.8000001000

rounded to one digit after decimal point

     towards nearest: +30.8000000000
towards +ve infinity: +30.9000000000
towards -ve infinity: +30.8000000000
        towards zero: +30.8000000000
      away from zero: +30.9000000000



number: -30.8000001000

rounded to one digit after decimal point

     towards nearest: -30.8000000000
towards +ve infinity: -30.8000000000
towards -ve infinity: -30.9000000000
        towards zero: -30.8000000000
      away from zero: -30.9000000000

http://coliru.stacked-crooked.com/a/fb29b19eea606eb3
I might be a little late - but here is the function - I guarantee it will do exactly what you want :D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
std::streamsize precision_d(double d)
{
    std::stringstream ss;

    ss.setf(std::ios::fixed);

    double d2;
    std::streamsize d_precision = 0;
    for(int i = 0; i <= 20; i++)
    {
       ss.precision(i);    
       ss << d;
       ss >> d2;
       if(d == d2) break;
  
      d_precision += 1; 
      ss.str(""); ss.clear();
    }
    return d_precision;
}
And the output :
out : 12383.5
rand_d() - prec : 1
prec_d() - prec : 1

out : 379.8
rand_d() - prec : 1
prec_d() - prec : 1

out : 4342.7
rand_d() - prec : 1
prec_d() - prec : 1

out : 6996.421
rand_d() - prec : 3
prec_d() - prec : 3

out : 12183.18
rand_d() - prec : 2
prec_d() - prec : 2

out : 1595.23837239
rand_d() - prec : 8
prec_d() - prec : 8

out : 10580.6
rand_d() - prec : 1
prec_d() - prec : 1

out : 5926.758431318416
rand_d() - prec : 12
prec_d() - prec : 12

out : 7136.553
rand_d() - prec : 3
prec_d() - prec : 3

out : 13142.3
rand_d() - prec : 1
prec_d() - prec : 1

out : 8811.83338991
rand_d() - prec : 8
prec_d() - prec : 8

out : 11370.53
rand_d() - prec : 2
prec_d() - prec : 2

out : 9274.3948171
rand_d() - prec : 7
prec_d() - prec : 7

out : 6981.1234684
rand_d() - prec : 7
prec_d() - prec : 7

out : 10075.6
rand_d() - prec : 1
prec_d() - prec : 1

out : 9462.86497529
rand_d() - prec : 8
prec_d() - prec : 8

out : 6045.22
rand_d() - prec : 2
prec_d() - prec : 2

out : 10205.918945682
rand_d() - prec : 9
prec_d() - prec : 9

out : 8302.293856
rand_d() - prec : 6
prec_d() - prec : 6

out : 6175.69117
rand_d() - prec : 5
prec_d() - prec : 5

out : 9438.27993725396
rand_d() - prec : 11
prec_d() - prec : 11

out : 13312.849463882481
rand_d() - prec : 12
prec_d() - prec : 12

out : 4821.91367
rand_d() - prec : 5
prec_d() - prec : 5

out : 10803.124761246519
rand_d() - prec : 12
prec_d() - prec : 12

out : 2055.7583673473
rand_d() - prec : 10
prec_d() - prec : 10


YEAH :D
Last edited on
+ random_d() function upgrade :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
double random_d(std::streamsize& input_precision)
{
     static bool need_random = true;

    if(need_random)
    {
        srand(static_cast<unsigned int>( time(NULL)) );
        need_random = false;
    }

    int n = (rand() % 9) + 1;
    if((rand() % 100) >= 85) n = 1;
    double a = (rand() % 15000);
    double b = 0;
    for(long long i = 0, j = 0; i < n; i++)
    {
        j = (rand() % 9) + 1;
        b = b * 10 + j;
    }
    input_precision = n;
    a += (b / std:: pow(10, input_precision));

    if((rand() % 100) >= 65) a = (-a);
    return a;
}
Last edited on
Here is the super-enhanced version of round_d() - so much powerful for a function :D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Rounds a double (custom round precision, negative rounding, round-up, round-down supported)

double round_d(double d,  std::streamsize input_precision, std::streamsize round_prec = 1, bool upDown = true)
{
    std::stringstream ss;
    ss.setf(std::ios::fixed);
    ss.precision(input_precision) ;
    ss << d;
    bool round = false;
    std::string out = ss.str();
    std::string::size_type n;
    std::size_t dot = out.find(".");
    if(dot != std::string::npos && (out.length() - 1 - dot) >= 1 + round_prec)
    {
        round = true;
        n = dot + 1 + round_prec;
    }
    else {
        n = out.length();
    }
    out.resize(n);
    ss.str(""); ss.clear();
    ss.str(out);
    ss >> d;

    if(round && (upDown == true) && d >= 0) d += (1.0 / pow(10, round_prec));
    if(round && (upDown == false) && d < 0) d -= (1.0 / pow(10, round_prec));

    return d;
}
My solution is now totally flawless :D

in : -9254.6832141
out : -9254.6

in : -11906.4
out : -11906.4

in : 11002.11522814
out : 11002.2

in : -5514.42499698997
out : -5514.4

in : 1720.788
out : 1720.8

in : 9022.17388
out : 9022.2

in : 14202.322185743617
out : 14202.4

in : 2857.91466944229
out : 2858.0

in : 10721.98274748978
out : 10722.0

in : 1133.3777116
out : 1133.4

in : -6860.21282
out : -6860.2

in : -13231.7
out : -13231.7

in : -9587.32759
out : -9587.3

in : 11980.4
out : 11980.4

in : 5798.13
out : 5798.2

in : -4918.724158794366
out : -4918.7

in : 14328.4
out : 14328.4

in : 935.6
out : 935.6

in : 6578.7957
out : 6578.8

in : 7354.92461764153
out : 7355.0

in : -6315.76412115779
out : -6315.7

in : 13528.7
out : 13528.7

in : 2490.8551
out : 2490.9

in : -12046.369
out : -12046.3

in : -7563.146581
out : -7563.1

in : 13079.2769856396
out : 13079.3

in : 1104.849343
out : 1104.9

in : -2202.52463462
out : -2202.5

in : 1632.457
out : 1632.5

in : 10494.6
out : 10494.6
Does that help you? : )
Now my solution is even better than before : The variable (input_precision) has become nolonger needed. Simpler design, more efficent code :)

If you want to get (input_precision) of a double, simply call precision_d(d) :-D

+ function random_d() :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
double random_d()
 {
     static bool need_random = true;

    if(need_random)
    {
        srand(static_cast<unsigned int>( time(NULL)) );
        need_random = false;
    }

    int n = (rand() % 12) + 1;
    if((rand() % 100) >= 85) n = 1;
    double a = (rand() % 15000);
    double b = 0;
    for(long long i = 0, j = 0; i < n; i++)
    {
        j = (rand() % 9) + 1;
        b = b * 10 + j;
    }
    std::streamsize input_precision = n;
    a += (b / std:: pow(10, input_precision));

    if((rand() % 100) >= 65) a = (-a);
    return a;
 }
+ function round_d() :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
double round_d(double d, std::streamsize round_prec = 1, bool upDown = true)
 {
    std::streamsize input_precision = precision_d(d);
        
    std::stringstream ss;
    ss.setf(std::ios::fixed);
    ss.precision(input_precision) ;
    ss << d;
    bool round = false;
    std::string out = ss.str();
    std::string::size_type n;
    std::size_t dot = out.find(".");
    if(dot != std::string::npos && (out.length() - 1 - dot) >= 1 + round_prec)
    {
        round = true;
        n = dot + 1 + round_prec;
    }
    else {
        n = out.length();
    }
    out.resize(n);
    ss.str(""); ss.clear();
    ss.str(out);
    ss >> d;

    if(round && (upDown == true) && d >= 0) d += (1.0 / pow(10, round_prec));
    if(round && (upDown == false) && d < 0) d -= (1.0 / pow(10, round_prec));

    return d;
 }
Does that help? :)
What solution do you think you see it is better? Mine or JLBorgers's? :)
JLBorgers'
closed account (48T7M4Gy)
https://support.microsoft.com/en-au/kb/214118
Pages: 12345