# Templated math

This topic is 4063 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm trying to make a simple math library (sqrt, pow, log, etc. ), but with templates instead of functions. E.g. const int a = 50; const int b = 2; const int c = log<a, b>::value; Now, I think I know how to do it with integers, but I is there a way to use floats? Floats can't be used as template parameters. They could be packed (casted) to ints or long longs (except long double), passed as parameters and unpacked, but is there an elegant way to cast bits of a float immediate value to int or long long? The same applies for unpacking, but this may be less elegant, since it will be hidden in the implementation. Anyways, supposing this problem is solved, the compiler might report too deep template recursion for floats, right?

##### Share on other sites
I have no idea what you are trying to do, maybe you could elaborate on that.

Casting the float "bits" to int "bits" can be done with a construct like that:

float f = 47.11f;
int& i = *((int*)&f);

And the other way round;

float& fr = *((float*)&i);

##### Share on other sites
Quote:
 Original post by RattenhirnI have no idea what you are trying to do, maybe you could elaborate on that.

It's template metaprogramming. I want the calculations to be done during compile time.

Quote:
 Casting the float "bits" to int "bits" can be done with a construct like that:float f = 47.11f;int& i = *((int*)&f);And the other way round;float& fr = *((float*)&i);However, I don't see how this would help your problem.

It won't :-) I need to cast immediate values like:

int i = something(4.7f); // i should contains bits of 4.7f NOT 4

##### Share on other sites
You could use a fixed-point representation (which means you really used integers). As you noted, floats cannot be non-type template arguments, so you're really out of luck there. Fixed-point is likely the best option you have.

##### Share on other sites
Unfortunately you cannot pack floats into ints without loss of information. That's why casting can be a dangerous thing to do. The computer representation of floats and ints is like comparing a slide rule and an abacus. The first uses logarithmic representation of decimal numbers, the second just counts numbers. They cannot be interchanged. Non-type template parameters are severely restricted at this point in time.

--random

##### Share on other sites
Quote:
 Original post by random_thinkerUnfortunately you cannot pack floats into ints without loss of information. That's why casting can be a dangerous thing to do. The computer representation of floats and ints is like comparing a slide rule and an abacus. The first uses logarithmic representation of decimal numbers, the second just counts numbers. They cannot be interchanged. Non-type template parameters are severely restricted at this point in time.--random

Assuming certain conditions, int and float both have 4 bytes. So there can't be a loss of information. I need to sth like *(int *) &4.7f

##### Share on other sites
You can't do it with casting, because reinterpreting an int as a float or vice-versa would require a reinterpret_cast (hence the name), which means operating on something in memory, which means doing the work at runtime (incompatible with the template, and defeating the purpose even if it could work). Template recursion won't be a problem unless you actually recurse :)

It would have to be done with some kind of macro I guess. Something like (making very non-portable assumptions of course):

#define F2I(x) /* you're on your own for this one. ;) */#define I2F(x) /* similarly */// Won't be able to call a function or look up in a table there - has to be// known compile-time-evaluable.template <int encoded_base, int encoded_operand>class log { static const float value; };template <int encoded_base, int encoded_operand>const float log::value = std::log(I2F(encoded_base), I2F(encoded_operand));const float log2of50 = log<F2I(2), F2I(50)>::value;

##### Share on other sites
OK...I stand corrected. Would something like this help:

Quote:
 A C SolutionFortunately, the 1999 ISO C Standard defines two functions which were not a part of earlier versions of the standard. These functions round doubles and floats to long ints and have the following function prototypes: long int lrint (double x) ; long int lrintf (float x) ; These functions are defined in but are only usable with the GNU C compiler if C99 extensions have been enabled before is included. This is done as follows: #define _ISOC9X_SOURCE 1 #define _ISOC99_SOURCE 1 #include Two versions of the defines ensure that the required functions are picked up with older header files. In the GLIBC (the standard version of the C library on Linux) header files, these functions are defined as inline functions and are in fact inlined by gcc (the standard C compiler on Linux) when optimisation is switched on. If optimisation is switched off, the functions are not inlined and an executable calling these functions will need to be linked with the maths library.

Edit---

There's a good thread already on this subject here. Apparently SiCrane indicated that MSVC6 allows double and float as non type parameters and most C++ compilers will allow references to const double.

Hope it's of use...

--random

[Edited by - random_thinker on October 2, 2007 1:05:12 PM]

##### Share on other sites
Quote:
 Original post by ZahlmanYou can't do it with casting, because reinterpreting an int as a float or vice-versa would require a reinterpret_cast (hence the name), which means operating on something in memory, which means doing the work at runtime (incompatible with the template, and defeating the purpose even if it could work). Template recursion won't be a problem unless you actually recurse :)It would have to be done with some kind of macro I guess. Something like (making very non-portable assumptions of course):#define F2I(x) /* you're on your own for this one. ;) */#define I2F(x) /* similarly */// Won't be able to call a function or look up in a table there - has to be// known compile-time-evaluable.template class log { static const float value; };template const float log::value = std::log(I2F(encoded_base), I2F(encoded_operand));const float log2of50 = log::value;

Well, that's actually what I DON'T want to do. You are using std::log which gets computed at runtime.

Now, I (probably, haven't done yet) know how do write a log template, like:
template <int number, int base>struct log {    static const int value = /* .... */;};

The difference with your example is tht I can use it everywhere a constant is needed, e.g. array declaration:

char digits[log<pow<2, sizeof(unsigned) * CHAR_BITS>::value, 10>::value + 1];

As for floats, theoretically it is possible to do all the calculations using emulated FP arithmetic, so it's definitely possible to use floats in templates.

Because of lack of other options, maybe use:

template <int mantissa, int exp = 0>struct tfloat {    static const int value = /* some bit shifts etc. according to IEEE 754 */;};

The use:

const float x = logf<tfloat<5, 2>, tfloat<3> >;

##### Share on other sites
Non-integral non-template type parameters can be used with pointers or references to non-integral objects with external linkage. Example:
template <const float & theta>struct Sin {  static float sin() {    return theta - theta * theta * theta / 6;  }};extern const float theta = 0.7853981633975f;extern const float sin_theta = Sin<theta>::sin();

Produces:
_TEXT	ENDSPUBLIC	?sin_theta@@3MB					; sin_theta_DATA	SEGMENT?sin_theta@@3MB DD 03f34641er			; 0.704653 ; sin_theta_DATA	ENDSEND

In MSVC 7.1 in a release build.

1. 1
Rutin
38
2. 2
3. 3
4. 4
5. 5

• 11
• 9
• 12
• 14
• 9
• ### Forum Statistics

• Total Topics
633350
• Total Posts
3011471
• ### Who's Online (See full list)

There are no registered users currently online

×