473,756 Members | 7,293 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Implementing a templated "round" function?

I need to implement a function to implement the rounding of floating point
values. At the moment i have two different implementations , depending on the
type of the return value (integer or double).

// 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)
}

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>(c onst 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>(s td::complex) )

I was thinking of using only one 'default' specialisation and using
std::numeric_li mits:

template <typename T, typename S>
T round(const S x)
{
if (std::numeric_l imits<S>::is_in teger)
// Integer type needs no rounding.
return static_cast<T>( x);

// Find rounding error.
const S round_error = std::numeric_li mits<S>::round_ error();

if (std::numeric_l imits<T>::is_in teger) {
// 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

Jul 22 '05 #1
6 4057
"Jef Driesen" <je********@nos pam.hotmail.com > wrote in message
news:cj******** **@ikaria.belne t.be...
I need to implement a function to implement the rounding of floating point
values. At the moment i have two different implementations , depending on the type of the return value (integer or double).

// 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)
}
The first function looks suspect because it loses precision. Anyway, if the
true and false clauses of operator ? are the same, you can avoid the
comparison.

Anyway, have you measured the time difference?
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);
}
Should that be

template <>
int round<int>(cons t double x) {
template <>
double round<double>(c onst 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>(s td::complex) )

I was thinking of using only one 'default' specialisation and using
std::numeric_li mits:

template <typename T, typename S>
T round(const S x)
{
if (std::numeric_l imits<S>::is_in teger)
// Integer type needs no rounding.
return static_cast<T>( x);

// Find rounding error.
const S round_error = std::numeric_li mits<S>::round_ error();

if (std::numeric_l imits<T>::is_in teger) {
// 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?


It's worthwhile to check the assembly to see if your compiler does the
optimization.

Anyway, you can put the numeric_limits: :is_integer into the function or
class template argument list. Here is the idea:

template <typename T, typename S>
inline
T round(const S x) {
return generic_round<T , S,T::is_integer >(x);
}

template <typename T, typename S, bool is_integer>
inline
T generic_round(c onst S x);

template <typename T, typename S>
inline
T generic_round<T ,S,true>(const S x) {
const S round_error = std::numeric_li mits<S>::round_ error();
return T(x + round_error);
}

etc
Jul 22 '05 #2

"Siemel Naran" <Si*********@RE MOVE.att.net> wrote in message
news:CS******** *************@b gtnsc05-news.ops.worldn et.att.net...
"Jef Driesen" <je********@nos pam.hotmail.com > wrote in message
news:cj******** **@ikaria.belne t.be...
I need to implement a function to implement the rounding of floating point values. At the moment i have two different implementations , depending on the
type of the return value (integer or double).

// 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)
}


The first function looks suspect because it loses precision.


IIRC the floating point representation of integer numbers is exact. If you
are talking about a possible under/overflow in the conversion from double to
int, you are correct. In the final code I will probably add code to prevent
under/overflows:

const R minimum = std::numeric_li mits<int>::min( );
const R maximum = std::numeric_li mits<int>::max( );
if (x < minimum)
return minimum;
else if (x > maximum)
return maximum;
Anyway, if the true and false clauses of operator ? are the same,
you can avoid the comparison.
This is a typo. The last "+0.5" should become "-0.5" in both functions.
Anyway, have you measured the time difference?
Yes I did and dround is (1.89 times) faster than iround, unless I
static_cast the result of dround to int (factor 0.73).
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);
}
Should that be

template <>
int round<int>(cons t double x) {


Another typo. But it don't think my syntax was incorrect.
template <>
double round<double>(c onst 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>(s td::complex) )

I was thinking of using only one 'default' specialisation and using
std::numeric_li mits:

template <typename T, typename S>
T round(const S x)
{
if (std::numeric_l imits<S>::is_in teger)
// Integer type needs no rounding.
return static_cast<T>( x);

// Find rounding error.
const S round_error = std::numeric_li mits<S>::round_ error();

if (std::numeric_l imits<T>::is_in teger) {
// 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?


It's worthwhile to check the assembly to see if your compiler does the
optimization.


MSVC7.1 does the optimization. I don't know about other compilers.
Anyway, you can put the numeric_limits: :is_integer into the function or
class template argument list. Here is the idea:

template <typename T, typename S>
inline
T round(const S x) {
return generic_round<T , S,T::is_integer >(x);
}

template <typename T, typename S, bool is_integer>
inline
T generic_round(c onst S x);

template <typename T, typename S>
inline
T generic_round<T ,S,true>(const S x) {
const S round_error = std::numeric_li mits<S>::round_ error();
return T(x + round_error);
}

etc


Looks interesting to me.
Jul 22 '05 #3
> // 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>(c onst 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>(s td::complex) )

I was thinking of using only one 'default' specialisation and using
std::numeric_li mits:

template <typename T, typename S>
T round(const S x)
{
if (std::numeric_l imits<S>::is_in teger)
// Integer type needs no rounding.
return static_cast<T>( x);

// Find rounding error.
const S round_error = std::numeric_li mits<S>::round_ error();

if (std::numeric_l imits<T>::is_in teger) {
// 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

Jul 22 '05 #4
"Jef Driesen" <je********@nos pam.hotmail.com > wrote in message
"Siemel Naran" <Si*********@RE MOVE.att.net> wrote in message
"Jef Driesen" <je********@nos pam.hotmail.com > wrote in message
// 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)
}
Anyway, have you measured the time difference?
Yes I did and dround is (1.89 times) faster than iround, unless I
static_cast the result of dround to int (factor 0.73).


Sorry, I'm a bit confused. I thought dround is slower. Are you saying that
dround is faster, but if you cast the return from double to int, then it is
slower?

IIRC the floating point representation of integer numbers is exact. If you
are talking about a possible under/overflow in the conversion from double to int, you are correct. In the final code I will probably add code to prevent under/overflows:

const R minimum = std::numeric_li mits<int>::min( );
const R maximum = std::numeric_li mits<int>::max( );
if (x < minimum)
return minimum;
else if (x > maximum)
return maximum;


Anyway, these checks will make iround slower, right? Maybe then dround is
better?
Jul 22 '05 #5
> > > > // 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)
> } Anyway, have you measured the time difference?
Yes I did and dround is (1.89 times) faster than iround, unless I
static_cast the result of dround to int (factor 0.73).


Sorry, I'm a bit confused. I thought dround is slower. Are you saying

that dround is faster, but if you cast the return from double to int, then it is slower?
In my previous post I swapped the time values by accident. But my
conclusions where still correct. A small example:

const double x = 1.5;
double a = dround(x); // Relative time is 0.73
int b = iround(x); // Relative time is 1.00
int c = static_cast<int >(dround(x)); // Relative time is 1.89

If the result needs to stay in floating point format, dround is faster. If
the result needs a static_cast to integer, iround is faster. I need this
conversion from double to int in many of my image processing applications,
where calculations are performed on floating point numbers (to prevent
under/overflows, integer divisions,...) but the final result should be an
integer type (often unsigned char).
IIRC the floating point representation of integer numbers is exact. If you are talking about a possible under/overflow in the conversion from

double to
int, you are correct. In the final code I will probably add code to

prevent
under/overflows:

const R minimum = std::numeric_li mits<int>::min( );
const R maximum = std::numeric_li mits<int>::max( );
if (x < minimum)
return minimum;
else if (x > maximum)
return maximum;


Anyway, these checks will make iround slower, right? Maybe then dround is
better?


Of course, but if I do add these checks to iround, I should add them also in
the code above when casting the result of dround to int.
Jul 22 '05 #6
> > // 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?


The first version is indeed slower than the second version one, because of
the (slow) cast from double to int. But in my applications (image
processing) I need to store the results of my calculations as integers. If I
use the second version, I need a static_cast anyway. In this case it's
faster to use the first function .
Jul 22 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

36
6396
by: Andrea Griffini | last post by:
I did it. I proposed python as the main language for our next CAD/CAM software because I think that it has all the potential needed for it. I'm not sure yet if the decision will get through, but something I'll need in this case is some experience-based set of rules about how to use python in this context. For example... is defining readonly attributes in classes worth the hassle ? Does duck-typing scale well in complex
81
7336
by: Matt | last post by:
I have 2 questions: 1. strlen returns an unsigned (size_t) quantity. Why is an unsigned value more approprate than a signed value? Why is unsighned value less appropriate? 2. Would there be any advantage in having strcat and strcpy return a pointer to the "end" of the destination string rather than returning a
1
1648
by: Ioannis Vranos | last post by:
I was checking .NET multithreading lately, and my book mentions that the thread scheduler provides quantoms of a time to each thread in "round robin" fashion. Is there any on line reference about it? I suppose it is just a circular fashion.
29
3372
by: Vol | last post by:
I think 'atan' can get the angle but it is not the four quadrant angle. Is there any function that i can get the angle from -pi to pi? or I have to use some if ... else? I know in Matlab, we use 'atan2( )' Also, is there any function to get the round value, similar with floor and ceil, such like: round(3.1) = 3 round(3.6) = 4
4
2417
by: Bob | last post by:
I have an Access application where I need to automatically forward emails to a group of 12 salespeople as soon as they arrive. The first email needs to go to the first salesperson on the list, the second email to the second salesperson on the list until I get to the end of the list, then start over. I also need to be able to exclude salespeople on their day off. The email portion of the application will be using a rule in Outlook 2003...
2
3831
by: =?Utf-8?B?aGVyYmVydA==?= | last post by:
how do I code generic functions to return the next item in an enumeration a) sorted by name, b) sorted by value c) sorted by declaration in a round-robin style ? for example the enum is Enum Colors Red = 5 Green = 7 Blue = 16 Yellow = 2
94
30340
by: Samuel R. Neff | last post by:
When is it appropriate to use "volatile" keyword? The docs simply state: " The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock Statement (C# Reference) statement to serialize access. " But when is it better to use "volatile" instead of "lock" ?
11
1850
by: moltendorf | last post by:
Hey everyone, as I have been by far pleased with some of the top helpers on this forum, I have decided to send another one your way. Even though I am personally having minimal issues with this script I have developed, I am wondering if someone could fix my little bug with it. This script runs perfectly fine, except once in a while, the color changing will "pause" because (according to Mozilla Firefox 3's error console) it is putting out...
2
4307
by: bips2008 | last post by:
The code seems to work fine in other browser but in IE it throws this error. This is very urgent for me and any help would be greatly appreciated For your convienence i have posted the code for the file. The portion that is not working is the star rating part <?php session_start(); include_once('includes/host_conf.php'); include_once('includes/db_connect.php'); include_once('includes/mysql.lib.php');...
0
9303
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9117
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9894
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8542
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6390
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4955
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5156
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3141
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2508
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.