Sign in to follow this  

floating point & fixed point again

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

hi there. so i've searched the internet for fixpoint tutorials, i've found some, but i'm still not ok with this subject. all my data from the exporter is floating point. now i'm building a converter to fixpoint. so, how do i do it? i've also got some integer values there. how can i convert them? i've seen in a tutorial here on gamedev that for integers shifting left 16 it's ok. on internet, i've seen shifting left just 8 positions it's ok. for floating point i've seen multipling with 256 (2^8). so in our case we will multiply by 2^16 ?. please somebody help me. thaks a lot for your patience.

Share this post


Link to post
Share on other sites
The amount you need to shift left depends on how many bits you are using for the whole part of the number, and how many are for the fractional part. OpenGL ES uses 16.16 format, that is the first 16 bits are for the whole part, the last 16 bits are for the fractional.

I've been putting together a fixed point number class that I was planning on posting here. Here is the current version, its stable but be aware that I havn't finished fully testing it. It doesn't do any range checking, so if you multiply two numbers that are too large, you'll have problems. The HAVE_FLOATS directive is used so for PC based tools I can easily convert from floats, but for native code it will get compiled out.


#ifndef _FIXED_H_
#define _FIXED_H_

#define HAVE_FLOATS

namespace Math
{
const int PRECISION = 16;
const int HALF_PRECISION = 8;
const int PRECISION_MASK = 0xFFFF;

class fixed
{
public:
int mValue;
private:
fixed(int value) : mValue(value)
{
}

public:

fixed() : mValue(0)
{
}

fixed & operator = (const fixed & rhs)
{
mValue = (rhs.mValue);
return *this;
}

void FromInt(const int value)
{
mValue = (value << PRECISION);
}

#ifdef HAVE_FLOATS
void FromFloat(const float value)
{
mValue = static_cast < int> (value * (1 << PRECISION));
}
#endif

int ToInt()
{
return (mValue >> PRECISION);
}

float ToFloat()
{
return ((float)mValue / PRECISION_MASK);
}

friend fixed operator * (const fixed & lhs, const fixed & rhs);
friend fixed operator * (const int lhs, const fixed & rhs);
friend fixed operator * (const fixed & lhs, const int rhs);

friend fixed operator / (const fixed & lhs, const fixed & rhs);
};

fixed operator * (const fixed & lhs, const fixed & rhs)
{
return fixed((lhs.mValue >> HALF_PRECISION) * (rhs.mValue >> HALF_PRECISION));
}

fixed operator * (const int lhs, const fixed & rhs)
{
return fixed(lhs * rhs.mValue);
}

fixed operator * (const fixed & lhs, const int rhs)
{
return fixed(lhs.mValue * rhs);
}

fixed operator / (const fixed & lhs, const fixed & rhs)
{
int temp = (lhs.mValue / rhs.mValue);
return fixed(temp << PRECISION);
}
}
#endif



Alan

Share this post


Link to post
Share on other sites
As you have said, the Tutorial on this site shows a one line macro for converting integers to fixed point, and the BREW site, if you choose the basic programming link or something, has a similar macro for converting floating point to fixed point.

Now, I find the rest of what you are saying to be quite interesting. First, whether it is an integer or a floating point value, the process is the same for both the macros I mentioned above, they just multiply the value by 2^16, but in the case of floating point, it takes only the non-fractional portion.

Now, when I first started working with the colors and vector values in GL ES, I found that things only worked out if I changed the macros to multiply by 2^8. I'm not certain why this is the case, as I cannot imagine that the BREW website would have the wrong macro for conversion, but perhaps someone should send a message to the OpenGL ES people, khronos or whatever.

Personally, I would stick to 2^8, otherwise all the values you send will be taken as being at minimum 256 times larger than what you intended.

Share this post


Link to post
Share on other sites
There's no error. If you want to convert a value, whether it's a float or an integer, to be interpreted as a 16.16 fixed point value, you have to multiply it by 2^16. Note that if the intial value was larger than 65535, this will cause an overflow.

I think I know what's causing confusion here. If you're dealing with vertex position data or texture coordinates, an integer value of 1 is treated exactly the same way as a floating point value of 1.0. So the conversion to fixed is the same for both representations.

But with colors, it's a different story. If you represent a color as an integer value, OpenGL internally normalizes those values. So an unsigned byte value of 255 isn't equivalent to 255.0, it's equivalent to 1.0.

If you try to convert an unsigned color value to a fixed point value, you first have to convert it to a floating point value. This would mean dividing by 255. Then you'd multiply by 2^16. Note that this is equivalent (or close enough) to multiplying by 2^8. You shouldn't do this conversion anyway, though, since you can use unsigned byte colors directly as long as you pass GL_UNSIGNED_BYTE to glColorPointer.

Share this post


Link to post
Share on other sites
hi. thanks a lot folks. today, before reading this, i've said to myself that all tutorials are wrong, and i have to think it up myself. so i took my pen and do some bit shifting and stuff (on the paper) and then all came to me: all tutorials were reffering to the old version of type "int" on 16 bits. so there was the problem. that's way everyone was shifitng with 8 bits for integers and multipling with 256 for floats(wich is the same, but you cannot shift float values without mess up things). so all i have to do is multiply by 65536.all ok. all libraries and classes on the internet wich implement fixed point operations are treating the fact that when you multiply 2 fixed point numbers, you also multiply the 65536 value, and so on. so you have to be carefull with that. well thank you alot guys for clearing my mind (especially with color things) and happy coding

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Correct me if i'm wrong, but you don't want to have a whole class with many methods to represent a such a simple type as fixed point number.

Share this post


Link to post
Share on other sites
what maybe wrong with this one?!!!

int tofix(float x)
{
return (int)(x * 65536);
}

i just don't have what i expect to have. i've just have some simple coordinates and the results are very unexpected.

Share this post


Link to post
Share on other sites
That shld work on the emulator though it's never going to run on the phone. There is no HW support for floating point operation and you cant link with the ARM lib. The only remaining option is to use the floating point helper functions provided by BREW. Anyway since you are using fixed point I dont really get why you still need floats.

f.

Quote:
Original post by meeshoo
what maybe wrong with this one?!!!

int tofix(float x)
{
return (int)(x * 65536);
}

i just don't have what i expect to have. i've just have some simple coordinates and the results are very unexpected.

Share this post


Link to post
Share on other sites
hi. well, that function was not from the application, it was from a tool, a converter. i convert data to fix point from float using that function, export it to a file, then load the file using Brew SDK interfaces and it should work. i've tried it with a cube and there is nothing on my simulator when i run the programming. only black. the opengl is initialised, because i've tested by manually drawing a triangle. also the model is already scaled so it should work.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster

When you use these fixed point numbers do you make sure you divide them back down by 65536 (2^16)? If not, they will remain large values and therefore nothing will be drawn because of out of range values when drawing.

when using fixed point arithmetic, dependant on the accuracy you require, you would multiply the point values up by 2^fractionalbits, when you require them as REAL values you need to divide them down by the same fractionalbits factor. if you are multiplying/dividing/subtracting/adding to these values you also need to make sure they are of the same factor afterwards.

oh and watch out for overflows aswell which is a common problem when using large integers with fixed point arithmetic.

Share this post


Link to post
Share on other sites
well i've printed some of the loaded numbers (with DBGPRINTF) and i saw that they are pretty big, but i was supposing that they are looking so because they should look so because the 16 bits are 0. well, i will try to play with them a little and see what is happening. thanks.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Anonymous Poster

When you use these fixed point numbers do you make sure you divide them back down by 65536 (2^16)? If not, they will remain large values and therefore nothing will be drawn because of out of range values when drawing.

What would be the point of that? OpenGL ES handles the fixed point numbers nativly.

Share this post


Link to post
Share on other sites
hi there. all pbs solved. infact, there was no problem with coordinates, but with drawing functions. it's ok to spend 5 hours to look out for that 1 single parameter that was partially wrong.

Share this post


Link to post
Share on other sites
Sign in to follow this