Algorithm to get the decimal part of a number

Hello, cplusplus.com
I'm writting an algorithm which equals to std::to_string. The inttostring part is fine, and the decimal_part too. But when the number digits > 5, the program loops infinitely.
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
#include <iostream>
#include <string>
#include <algorithm>
std::string inttostring(int num)
{
    std::string return_;
    bool is_negative = false;
    if(num < 0)
    {
        is_negative = true;
        num = -num;
    }
    if(num == 0) return "0";

    while(num) //the algorithm
    {
        int rem = num % 10;
        num /= 10;
        return_.push_back(rem + '0');
    }
    std::reverse(return_.begin(), return_.end());
    return is_negative? std::string("-")+ return_ : return_;
}

std::string decimal_part(double num)
{
    if(num == (int)num)
        return "0";
    else
    {
        double onlydecimal = num - (int)num;
        while(onlydecimal - (int)onlydecimal) onlydecimal *= 10;
            return inttostring(onlydecimal);
    }
}
int main(int argc, char* argv [])
{
    std::cout << inttostring(0.1234) + "." + decimal_part(0.1234);
}

In this code, the program runs ok. But try to add a 5 at decimal_part.
What should I do to get this 'decimal_part' ok?

Thanks! =)
In floating point math, there is no guarantee that 6.0 - 6 will always equal 0. It could equal 0.00000000001 or something like that. This is why your while-loop is not exiting as expected.

You can decide to do something like:
1
2
3
4
while(onlyDecimal <= /**/ 1000 /**/)
{
    onlyDecimal *= 10;
}


1
2
3
4
5
6
7
8
9
std::string decPart;
for( int d = 0; d < 3; d++ )
{
    onlyDecimal *= 10;
    decPart += inttostring(static_cast<int>(onlyDecimal));
    onlyDecimal -= static_cast<int>(onlyDecimal);
}

return inttostring(static_cast<int>(num)) + '.' + decPart;


*Note the 1000 represents the number of decimal places you want this function to be accurate to. In this case I chose 4 ( log10(1000) + 1 ~ 4). The for loop will run however many times you want the decimal part to be accurate to. I chose 3 in this case, you can of course decide to leave this option up to the user for them to decide.
Last edited on
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
#include <iostream>
#include <string>
#include <type_traits>
#include <sstream>
#include <iomanip>
#include <locale>
#include <limits>

template < typename T >
typename std::enable_if< std::is_floating_point<T>::value, std::string >::type
decimal_part( T number, int ndigits = 6 )
{
    if( ndigits < 1 ) return "" ;

    std::ostringstream stm ;
    stm << std::fixed << std::setprecision(ndigits) << number ;
    auto str = stm.str() ;
    return str.substr( str.find( std::use_facet< std::numpunct<char> >( stm.getloc() ).decimal_point() ) + 1 ) ;
}

int main()
{
    const double n = -2 / 3.0 ;
    std::cout << decimal_part(n) << '\n' // 666667
              << decimal_part( n, 3 ) << '\n' // 667
              << decimal_part( n, 8 ) << '\n' // 66666667
              << decimal_part( n, std::numeric_limits<double>::digits10 ) << '\n' ; // 666666666666667 (typical)
}

http://coliru.stacked-crooked.com/a/5faf069ec2e84c1d
You should read this :
What Every Computer Scientist Should Know About Floating-Point Arithmetic
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
If it gets scary you are free to close the tab.
Last edited on
@Smack89 thanks :)
@JLBorges I don't know how many digits will the user enter and I need to use a algorithm.
@a k n Just opened and closed xD Ok, I know simple things as log, e^x, integrals, "dx", but I'm only thirteen. That kind of sum with millons of d's is too complicated for me. Anyway, thank you for the information!

If someone know where does the decimal part start (location in bytes, eg. 4th byte), I can use bitwise.
If someone know where does the decimal part start (location in bytes, eg. 4th byte), I can use bitwise.

That scary article also explains that and I warn you IEEE floating point format is itself scary , non-portable (different versions and formats).
But this might help you
http://en.wikipedia.org/wiki/Floating_point

I think you are a bit mistaken.
Let's get to the basics. Say you have a number p = 43.14159 in base 10 represented as 43.1415910
What does that mean ?
It means that p = 4*101 + 3*100 + 1*10-1+ 4*10-2 + ...
I hope you remember that from math class .
So , similarly a number can be expressed in binary like n = 11.0112 .
So , n = 1*21+1*20+0*2-1+1*2-2+1*2-3
which implies n = 3.375 in decimal .
But you cannot express every fraction as such in a base .
For example consider 1/3 which =
0.3333...10 in base 10 and
0.010101...2 in base 2 but
0.13 in base 3
Now you see the problem , not every number can be expressed in finite sequences ( 'recurring digits' recall from your math class ) so they are only expressed as a close approximation in floating point numbers.
Here's how 1/3 if in is expressed in most desktops (little-endian) in a double-precision number.
555555555555d53f16 , it would be 64 bits in binary.

So as smack89 suggested you should edit your method.

Hope that helps.
Last edited on
> I don't know how many digits will the user enter and I need to use a algorithm.

Read the input (a number in fixed point format) as a string.
Get the substring after the decimal point.
Convert the input to double with std::stod()
Topic archived. No new replies allowed.