Re: Implementing a templated "round" function?

From: Marcin Kalicinski (kalita_at_poczta.onet.pl)
Date: 09/30/04


Date: Thu, 30 Sep 2004 14:00:58 +0200


> // Integer calculation (fast)
> int iround(const double x) {
> return (x>=0 ? static_cast<int>(x + 0.5) : static_cast<int>(x + 0.5)
> }
> // Floating point calculation (slow)
> double dround(const double x) {
> return (x>=0 ? floor(x + 0.5) : ceil(x + 0.5)
> }

Why do you think the 1st version is integer calculation and is fast? It is
floating point calculation just as the 2nd version is.

What's more, on the 80x86 platform the first version will be actually a lot
slower than the second.

Have you profiled them?

Cheers,
Marcin

>
> But then I have 2 different functions for the same functionality. To solve
> this, I created a template function with 2 specialisations:
>
> template <typename T> T round(const double x);
> template <>
> int round(const double x) {
> return iround(x);
> }
> template <>
> double round<double>(const double x) {
> return dround(x);
> }
>
> I can add specialisations for the other data types (float, long, short,
> char, signed/unsigned,...) as well. I did not add a 'default'
> specialisation, because the round function is only usefull for numeric
> types. At this time my function accepts only double precision floating
point
> values, and I would like to have equivalent functions for float, double
and
> long double. I did add a second template parameter S for the source type:
>
> template <typename T, typename S>
> T round(const S x) {
> ...
> }
>
> The problem is now how do I implement this function?
>
> I could add a specialisation for every combination of S and T, but this is
a
> lot of work, and there are only 4 usefull implementations possible:
> - S and T are floating point type -> implementation using floor/ceil
> (dround)
> - S is a floating point type and T an integer type -> implementation using
> static_cast (iround)
> - S is an integer type and T is an integer or floating point type ->
simply
> static_cast to T
> - otherwise no implementation is necessary (should not compile if this is
> possible, to prevent e.g. round<double>(std::complex) )
>
> I was thinking of using only one 'default' specialisation and using
> std::numeric_limits:
>
> template <typename T, typename S>
> T round(const S x)
> {
> if (std::numeric_limits<S>::is_integer)
> // Integer type needs no rounding.
> return static_cast<T>(x);
>
> // Find rounding error.
> const S round_error = std::numeric_limits<S>::round_error();
>
> if (std::numeric_limits<T>::is_integer) {
> // Integer calculation (fastest).
> return (x>=0 ? static_cast<T>(x + round_error) : static_cast<T>(x +
> round_error)
> } else {
> // Floating point calculation (slower).
> return (x>=0 ? floor(x + round_error) : ceil(x + round_error)
> }
> }
>
> But this will results in a performance degradation if the compiler is
unable
> to optimize (eliminate) the 'if' statements. And the function has also an
> implementation for data types other then integer and floating point types.
> Any advice on this problem?
>
> --
> Jef Driesen
>
>
>



Relevant Pages

  • Implementing a templated "round" function?
    ... I need to implement a function to implement the rounding of floating point ... I created a template function with 2 specialisations: ... specialisation, because the round function is only usefull for numeric ... template <typename T, typename S> ...
    (comp.lang.cpp)
  • Re: partial specialization
    ... (other than syntax, of course)? ... The former is specialisation, ... specializezed for double and int, the later is a definition of A::foo ... It depends on the contents of struct Adefinition, ...
    (microsoft.public.vc.language)
  • Re: partial specialization
    ... (other than syntax, of course)? ... The former is specialisation, ... specializezed for double and int, the later is a definition of A::foo ...
    (microsoft.public.vc.language)