Question about ROUNDING_ERROR_?
Question about ROUNDING_ERROR_?
I saw that in 'vector2d.h' the equals fuction got a new parameter "T tolerance = (T)ROUNDING_ERROR_f32".
Aside from the fact, that this is not totally correct - casting to "T" is not the same as using ROUNDING_ERROR_"T", but it's a little tricky to do it right [see the boost library for examples] - it's probably good enaugh, because Irrlicht is working internally with float (=f32) most of the time, and CuteAlien mentioned it.
And there are a lot of other NON-template functions that also use ROUNDING_ERROR_f32.
But in 'matrix4.h' i found "bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;".
Is that ok for a float-matrix ( core:.matrix4 is defined as CMatrix4<f32> )?
If mostly f32 is used, wouldn't (T)ROUNDING_ERROR_f32 be better?
Aside from the fact, that this is not totally correct - casting to "T" is not the same as using ROUNDING_ERROR_"T", but it's a little tricky to do it right [see the boost library for examples] - it's probably good enaugh, because Irrlicht is working internally with float (=f32) most of the time, and CuteAlien mentioned it.
And there are a lot of other NON-template functions that also use ROUNDING_ERROR_f32.
But in 'matrix4.h' i found "bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;".
Is that ok for a float-matrix ( core:.matrix4 is defined as CMatrix4<f32> )?
If mostly f32 is used, wouldn't (T)ROUNDING_ERROR_f32 be better?
Re: Question about ROUNDING_ERROR_?
Answer is - it would have been better if the same default parameter would have been used throughout. But well, that was no longer possible, so I used at least the same one as in vector3d which is rather similar to vector2d. Changing it once it is set is probably a bad idea as changing API interface is always a bad idea unfortunately (I already have a bad feeling for the one I added now, but it had none before and I needed it a few times already and it likely doesn't mess up too many things).
If you can give me a concrete example in boost how they use different defaults based on type I'll check it out (don't want to search through all boost-library headers now or it'll probably take the rest of the week as big as that library is ...).
I'm also rather unhappy that operator== is using equals (and wish operator <, > etc wouldn't even be there), but I guess that's another thing I can't change anymore without breaking the interface for not a good enough reason.
If you can give me a concrete example in boost how they use different defaults based on type I'll check it out (don't want to search through all boost-library headers now or it'll probably take the rest of the week as big as that library is ...).
I'm also rather unhappy that operator== is using equals (and wish operator <, > etc wouldn't even be there), but I guess that's another thing I can't change anymore without breaking the interface for not a good enough reason.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Question about ROUNDING_ERROR_?
> If you can give me a concrete example in boost ...
It must not necessarily be boost ( i only mentioned it because right now i am using it, hehe ). You can find something similar in std::numeric_limits<T>. For example std::numeric_limits<int>::max() will be INT_MAX and std::numeric_limits<float>::max() will be FLOAT_MAX ( be carefull with std::numeric_limits<T>::min() - there is also std::numeric_limits<T>::lowest(), which is a completely different thing ! ).
So what we would need is something like
..., const T tolerance = ROUNDING_ERROR_<T>
which would give ROUNDING_ERROR_f32 for float and ROUNDING_ERROR_f64 for double and so on.
I can try to figure something out and if so, will post it here.
-----
> so I used at least the same one as in vector3d which is rather similar to vector2d.
My question was not about vector2d using the same parameter as vector3d - OF COURSE it should be that way.
My question was about matrix4.h. There is a function
bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
The last parameter is ROUNDING_ERROR_f64, which is for type double. So if T is float ( which probably nearly always it will be ), it will be casted to float and the value is 0.0.
Wouldn't it be better to use ROUNDING_ERROR_f32 ???
Then at least you are "secure" ( as with vector2d and vector3d and all the other templates and fuctions ).
It must not necessarily be boost ( i only mentioned it because right now i am using it, hehe ). You can find something similar in std::numeric_limits<T>. For example std::numeric_limits<int>::max() will be INT_MAX and std::numeric_limits<float>::max() will be FLOAT_MAX ( be carefull with std::numeric_limits<T>::min() - there is also std::numeric_limits<T>::lowest(), which is a completely different thing ! ).
So what we would need is something like
..., const T tolerance = ROUNDING_ERROR_<T>
which would give ROUNDING_ERROR_f32 for float and ROUNDING_ERROR_f64 for double and so on.
I can try to figure something out and if so, will post it here.
-----
> so I used at least the same one as in vector3d which is rather similar to vector2d.
My question was not about vector2d using the same parameter as vector3d - OF COURSE it should be that way.
My question was about matrix4.h. There is a function
bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
The last parameter is ROUNDING_ERROR_f64, which is for type double. So if T is float ( which probably nearly always it will be ), it will be casted to float and the value is 0.0.
Wouldn't it be better to use ROUNDING_ERROR_f32 ???
Then at least you are "secure" ( as with vector2d and vector3d and all the other templates and fuctions ).
Re: Question about ROUNDING_ERROR_?
Ah yeah, using defaults like that would probably work. And yes, I got that about CMatrix, what I meant above is that I had the choice of making it like CMatrix or like vector3d and so decided to make it like the latter. And that I don't want to change CMatrix because changing interfaces is nearly always bad even if it makes the interface better. Library interface just shouldn't ever change without really good reason (nearly every time I broke that rule I regreted it later on, so I'm slowly learning not to do that).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Question about ROUNDING_ERROR_?
Ok ok.
The PRINCIPAL decision NOT to change CMatrix i understand.
But if CMatrix is mostly of type float, in the function
bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
ROUNDING_ERROR_f64 ( which is 0.00000001 ) will be casted to float and then will be 0.0 and therefore "useless".
MAYBE changing ROUNDING_ERROR_f64 to ROUNDING_ERROR_f32 will solve some nasty problems / bugs that sometimes occur and sometimes not.
And you would not really change the interface because the parameter is default and as far as i saw never used / changed.
And quaternion also uses ROUNDING_ERROR_f32 !
The PRINCIPAL decision NOT to change CMatrix i understand.
But if CMatrix is mostly of type float, in the function
bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
ROUNDING_ERROR_f64 ( which is 0.00000001 ) will be casted to float and then will be 0.0 and therefore "useless".
MAYBE changing ROUNDING_ERROR_f64 to ROUNDING_ERROR_f32 will solve some nasty problems / bugs that sometimes occur and sometimes not.
And you would not really change the interface because the parameter is default and as far as i saw never used / changed.
And quaternion also uses ROUNDING_ERROR_f32 !
Re: Question about ROUNDING_ERROR_?
Ok, that we are losing that value on cast completely is a good argument. Although on quick test it doesn't actually seem to happen (the value used is a little suspicious anyway - in most (but not all) cases the better solution would be working with the ulp really). But I guess having the template parameter be based on the template is probably the best solution. I'll put it on my ever-growing todo.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Question about ROUNDING_ERROR_?
Just a small "update":
in
inline bool CMatrix4<T>::isIdentity() const
you check the individual elements with 'core::equals(...)' WITHOUT a parameter for tolerance.
This then will use ROUNDING_ERROR_f32, because the template for float is created.
In
inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
you use
core::equals( M, other.M, tolerance )
but here already the value for tolerance is "casted away" to 0.0 !
Maybe we could just leave away tolerance, as in function 'isIdentity'.
Another question:
There also is the 'operator==', which checks all elements without tolerance.
So there is a difference between "exactly equal" and "practically almost nearly equal".
Is that intended?
in
inline bool CMatrix4<T>::isIdentity() const
you check the individual elements with 'core::equals(...)' WITHOUT a parameter for tolerance.
This then will use ROUNDING_ERROR_f32, because the template for float is created.
In
inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
you use
core::equals( M, other.M, tolerance )
but here already the value for tolerance is "casted away" to 0.0 !
Maybe we could just leave away tolerance, as in function 'isIdentity'.
Another question:
There also is the 'operator==', which checks all elements without tolerance.
So there is a difference between "exactly equal" and "practically almost nearly equal".
Is that intended?
Re: Question about ROUNDING_ERROR_?
Even smaller update 2 (the last one, promised):
In 'quaternion.h" there is the function
inline void quaternion::toEuler(vector3df& euler) const
which calls
const f64 test = ...;
if( core::equals( test, 1.0, 0.000001 ) )
with the parameter for tolerance - which is ROUNDING_ERROR_f32 - HARDCODED !
Again - why not leave it away, then the fuction core::equals would automatically choose the right one.
In 'quaternion.h" there is the function
inline void quaternion::toEuler(vector3df& euler) const
which calls
const f64 test = ...;
if( core::equals( test, 1.0, 0.000001 ) )
with the parameter for tolerance - which is ROUNDING_ERROR_f32 - HARDCODED !
Again - why not leave it away, then the fuction core::equals would automatically choose the right one.
Re: Question about ROUNDING_ERROR_?
Thanks for pointing out those. I don't know the reasons for each of those lines. Basically I guess it's about having to bother the user as little as possible with that and shield him from the majority of floating point troubles (although doesn't explain the hardcoding certainly). But then parameters got added (like I did recently) simply because the defaults don't work well sometimes. Maybe I shouldn't have done that.
operator== should in my opinion care about equality in memory - so using direct comparisons and no epsilons. So I like the way it's done in the matrix and don't like the way it's done in the vector classes.
I also think if we use an epsilon that can be passed then all functions using that function should also pass the epsilon (another reason not to use them in operators).
I also don't know if using the epsilons like that is a good idea anyway and if we wouldn't get better results (but probably slower...) using either a combination of ulp-checks and special checks for 0 or reinterpreting the values as integers and doing direct comparisions allowing a difference of 1 (then each directly neighboring float would be considered equal). But I don't plan to work on this in Irrlicht, I already can't handle the tasks on my plate.
edit: The fact that there is lot of code in Irrlicht which got added without looking at existing code first is also driving me crazy once in a while (by which I mean no more often than 2-3 times per day usually). Still - fixing a library interface piece by piece is mostly worse than just leaving it (because it breaks user-code then all the time which is the worst sin any library can do).
operator== should in my opinion care about equality in memory - so using direct comparisons and no epsilons. So I like the way it's done in the matrix and don't like the way it's done in the vector classes.
I also think if we use an epsilon that can be passed then all functions using that function should also pass the epsilon (another reason not to use them in operators).
I also don't know if using the epsilons like that is a good idea anyway and if we wouldn't get better results (but probably slower...) using either a combination of ulp-checks and special checks for 0 or reinterpreting the values as integers and doing direct comparisions allowing a difference of 1 (then each directly neighboring float would be considered equal). But I don't plan to work on this in Irrlicht, I already can't handle the tasks on my plate.
edit: The fact that there is lot of code in Irrlicht which got added without looking at existing code first is also driving me crazy once in a while (by which I mean no more often than 2-3 times per day usually). Still - fixing a library interface piece by piece is mostly worse than just leaving it (because it breaks user-code then all the time which is the worst sin any library can do).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
Re: Question about ROUNDING_ERROR_?
quaternion is easy - this code was provided by someone else, so all interface and everything has been different ever since. Don't know where Niko got that code from, but it's really hard to integrate it. But I guess the rest should also be smoothed at some point, even if we break some things. These minor changes are not really breaking code, but are only not binary compatible. That's ok IMHO for a cleaner API.
Moving to bug forum also
Moving to bug forum also
Re: Question about ROUNDING_ERROR_?
There is a library with name "G3D Innovation Engine". I sometimes look into the sources just to see how they do mathematical operations. For example they have an epsilon that "adjusts" to the size of the numbers (with size i don't mean float32 or float64, but how big or small a number is). For small numbers epsilon also gets smaller and the other way around. Maybe that's too much effort and maybe you don't really need it in games (only in simulations).
I will have a closer look at these problems - need to solve them for my work anyway.
I will have a closer look at these problems - need to solve them for my work anyway.