PeddleSpam
PeddleSpam

Reputation: 438

Split floating point number into fractional and integral parts

I'm writing a template class designed to work with any floating point type. For some of the methods I need to split a number into its integral and fractional parts. With primitive floating point types I can just cast to an integer to truncate the fractional part, but this wouldn't work with a big number class. Ideally my class would only use the four basic arithmetic operations (addition, subtraction, multiplication, division) in its calculations.

The method below is the solution I came up with. All it does is subtract powers of ten until the original number is less than 1. It works well, but seems like a brute-force approach. Is there a more efficient way to do this?

template< typename T >
class Math
{
    public:

    static T modf( T const & x, T & intpart )
    {
        T sub = 1;
        T ret = x;

        while( x >= sub )
        {
            sub *= 10;
        }

        sub /= 10;

        while( sub >= 1 )
        {
            while( ret >= sub )
            {
                ret -= sub;
            }

            sub /= 10;

        }//while [sub] > 0

        intpart = x - ret;

        return ret;
    }
}

Note that I've removed the sign management code for brevity.

Upvotes: 2

Views: 2765

Answers (3)

Steve Jessop
Steve Jessop

Reputation: 279245

You could perhaps replace the subtraction loop with a binary search, although that's not an improvement in complexity class.

What you have requires a number of subtractions approximately equal to the sum of the decimal digits of x, whereas a binary search requires a number of addition-and-divide-by-two operations approximately equal to 3-and-a-bit times the number of decimal digits of x.

With what you're doing and with the binary search, there's no particular reason to use powers of 10 when looking for the upper bound, you could use any number. Some other number might be a bit quicker on average, although it probably depends on the type T.

Btw, I would also be tempted to make modf a function template within Math (or a free template function in a namespace), rather than Math a class template. That way you can specialize or overload one function at a time for particular types (especially the built-in types) without having to specialize the whole of Math.

Example:

namespace Math
{
    template <typename T>
    T modf( T const & x, T & intpart )
    { ... }
}

Call it like this:

float f = 1.5, fint;
std::cout << Math::modf(f, fint) << '\n';

double d = 2.5, dint;
std::cout << Math::modf(d, dint) << '\n';

mpf_class ff(3.5), ffint(0);  // GNU multi-precision
std::cout << Math::modf(ff, ffint) << '\n';

Overload it like this:

namespace Math {
    double modf(double x, double &intpart) {
        return std::modf(x, &intpart);
    }

    mpf_class modf(const mpf_class &x, mpf_class &intpart) {
        intpart = floor(x);
        return x - intpart;
    }
}

Upvotes: 2

Ed King
Ed King

Reputation: 1863

I don't know how strict your "ideally use only mathematical operations" restraint is, but nonetheless for the fractional part, could you extract it to a string and convert back to a float?

Upvotes: 0

ForEveR
ForEveR

Reputation: 55887

mb use std::modf is better? for custom type you can release Math class specialization.

#include <cmath>
#include <iostream>

template<typename T>
class Math
{
public:
    static T modf(const T& x, T& integral_part)
    {
        return std::modf(x, &integral_part);
    }
};

int main()
{
    double d_part = 0.;
    double res = Math<double>::modf(5.2123, d_part);
    std::cout << d_part << " " << res << std::endl;
}

Upvotes: 0

Related Questions