fixed point vs floating point

I would like to know if there is a way to use fixed point values instead of floating point values in hardware accelerated rendering (OpenGL/DirectX) or do I have to convert all rendering relevant values to float every frame?

I don't mind if fixed point is a little bit slower than floating point but I think fixed point would work better for my game (RTS) than floating point since fixed point has deterministic results across platforms and fixed precision.

Is fixed point still useable in todays games or would you just throw doubles at thinks where float is not enough?
I think that for storing large positions in fixed point still makes sense today. Especially when you are talking about large space games.

Modern GPU's for 3D rendering operate on floats. So you will need to convert to floats. D3D10 level hardware accepts integers though and can perform operations on integers, but they still need to convert everything down to float in vertex shader before calculating pixel/fragment position on screen. So you could pass fixed point values as integers to GL/D3D API, but you might as well do it yourself (because maybe you could do it more efficiently).
Dragonmaster047
I would like to know if there is a way to use fixed point values instead of floating point values in hardware accelerated rendering (OpenGL/DirectX) or do I have to convert all rendering relevant values to float every frame?

Yes. Only version of OpenGL that supported fixed point was OpenGL ES 1.0, and even that had profile for floating point. ES 2.0 and forward use floating point.

DirectX never had a (publicly released) version with fixed point support.


Dragonmaster047
I don't mind if fixed point is a little bit slower than floating point but I think fixed point would work better for my game (RTS) than floating point since fixed point has deterministic results across platforms and fixed precision.


Slower? As far as I know, fixed point beats floating point in speed.. at least with the normal plus/minus/mul/div operations. Anything above that will require more work and you'll probably find floating point hardware that does it faster..

As for accuracy, I'd love it if we'd have 64.64 fixed point support in hardware =) Enough range, no floating point accuracy problems, but then again, no NaNs or infs either, which may be a problem.


Dragonmaster047
Is fixed point still useable in todays games or would you just throw doubles at thinks where float is not enough?


There are situations where I've found fixed point to be the only math-accurate way to do things (where repeated float operations cause too much error to creep in eventually).

I don't know about SSE2-based float math, but the good old x87-based math is pretty hard to make cross-platform compatible. Unless you tell the fpu not to, it will keep temporary values in higher precision internally (which may be 80 or 64 bit depending on the vendor), and moving in and out of these temp values will quite probably change from one compile to the next, so you won't even be "cross-platform compatible" even on a single platform..

Now, you CAN tell the fpu to use different precision (then again, so can any of the libraries you're linking to, like directx). And you can tell most if not all of the C compilers how to handle precision, so the situation may not be as bad as it used to be.
sol_hsa
Slower? As far as I know, fixed point beats floating point in speed.. at least with the normal plus/minus/mul/div operations.

A claim like "fixed point beats floating point in speed" is impossible to either make or refute without a lot of context. Apart from division, all of those operations are fully pipelined on a modern CPU, so if you can keep the pipeline busy, they all take one (amortised!) cycle.

In addition, consider that many fixed-point operations require more than one instruction, with a data dependency between them. And on some older CPUs (warning: this caveat may be absurdly out of date) the floating point multiplier and the integer multiplier literally use the same circuit.

sol_hsa
I don't know about SSE2-based float math, but the good old x87-based math is pretty hard to make cross-platform compatible.

Oh yes. Numeric programmers from that era know all too well how badly x87 can screw up your numerics.

1
2
3
4
float x = some_operation();
if (x > 0) {
    assert(x != 0); // This assertion could fail on optimised builds
}
Pseudonym73
sol_hsa
Slower? As far as I know, fixed point beats floating point in speed.. at least with the normal plus/minus/mul/div operations.

A claim like "fixed point beats floating point in speed" is impossible to either make or refute without a lot of context. Apart from division, all of those operations are fully pipelined on a modern CPU, so if you can keep the pipeline busy, they all take one (amortised!) cycle.


Ha, my optimization mindset is teeny bit out of date.. =)

(regarding context - as an example, the microcontroller 8051 has a faster mul than shift by n, so context is everything..)


Pseudonym73
In addition, consider that many fixed-point operations require more than one instruction, with a data dependency between them. And on some older CPUs (warning: this caveat may be absurdly out of date) the floating point multiplier and the integer multiplier literally use the same circuit.


I can't remember any architecture (at least x86 one) that had same circuit for floats and ints.. at some point it actually made sense to mix float and int operations because they could be executed side by side (both taking more than one clock).


Pseudonym73
sol_hsa
I don't know about SSE2-based float math, but the good old x87-based math is pretty hard to make cross-platform compatible.

Oh yes. Numeric programmers from that era know all too well how badly x87 can screw up your numerics.

1
2
3
4
float x = some_operation();
if (x > 0) {
    assert(x != 0); // This assertion could fail on optimised builds
}


Fun =)

A friend of mine did a physics-based game with online score board long time ago, and found that linux and windows versions replayed the physics slightly differently, and there were other issues like that as well..

People (naturally) cheated on the online score board, one way to find the cheaters would have been to send the commands and re-playing the simulation as verification, but because different machines played the simulation slightly differently, that didn't work out.

The same problem also plagued some complex online games, where it "should" be possible just to send the commands for objects that are not totally simulated and then running the simulation and resulting in the same state for all players (let's just ignore latency issues here) - due to the fact that float accuracy couldn't be trusted, the results may differ.

I don't know if you could solve the above issues in current (post-sse2) machines. It would be nice.

Edited by Jari Komppa on
Pseudonym73

Oh yes. Numeric programmers from that era know all too well how badly x87 can screw up your numerics.

1
2
3
4
float x = some_operation();
if (x > 0) {
    assert(x != 0); // This assertion could fail on optimised builds
}


This bug would be impossible to make in assembly, so to blame the x87 for what is a C implementation bug, just isn't right.

The x87 is straight forward to program in assembly. It is infact very well designed, and it's syntax is logic, simple and intuitive.
x87 is awful. Doing floating point in SSE is so much better and much efficient. Not only because of SIMD, but also because of more sane registers - they are non stack based, so you can rearrange independent calculations to do them in parallel. Also no worrying and making silly mistakes about stack overflow or underflow (irrelevant for C, but relevant if you write x87 assembly).
No it's not awful. All assembly code is beautiful. But in particular, the x87 is very easy and intuitive to code.

It took me less time to verify it would be impossible to make this bug in assembly, than it takes to execute Visual Studio. In fact, I can code a descent windows application, before it is ready.

THAT is what is awful :D
Yes, assembly is beautiful. But there are some assembly dialects that are very nice, and some not so much.

Of course it is possible to make this bug in assembly. Why do you think it isn't? If compiler can produce buggy asm code, so can human. If anything, then compilers could produce significantly less buggy code than human in general (because it could automatically verify result). Whether they do that, that's a different question.

Edited by Mārtiņš Možeiko on
mmozeiko
Yes, assembly is beautiful. But there are some assembly dialects that are very nice, and some not so much.


That's a matter of taste. I never seen a good argument for syntax choices, and that is the reason.

All syntax are symbols. Labels. Only that. So what you chose are less important, since there are as many tastes as there are coders. And when you get used to one, you will understand it and then it will make sense.

By then, you will think it is a good one. So saying that one is better, than any other is a fallacy. You may say that the one that is prefered by most coders, is the best, cause then we can read each others code more easily. Like in a team or something. But it is "good" then, only because of habit.

C++ has awful syntax, according to my tastes. It even is more than a question of taste, because its syntax is 3 times as verbose as assembly. With 10 times as many complicating components. That in addition, comes from logical problems with the language itself, and not from logic. But it seems many people still love it, or at the very least: like it well enough to stick to it.

mmozeiko

Of course it is possible to make this bug in assembly. Why do you think it isn't? If compiler can produce buggy asm code, so can human. If anything, then compilers could produce significantly less buggy code than human in general (because it could automatically verify result). Whether they do that, that's a different question.


Fair enough. But the reason I say it, like that, is that this is a bug comming from not understanding how the x87 works. And that is not possible in asm. Of course, all people could make a bug. But when an asmer made this bug, would be because he was a beginner, or made a typo.

I commented because it seemed to me, like "Pseudonym73" was trying to blame the x87 for a C implementation bug. This isn't a problem with x87 or logic (assembly) but with not knowing what you are doing.
Kladdehelvete
All syntax are symbols. Labels. Only that. So what you chose are less important, since there are as many tastes as there are coders. And when you get used to one, you will understand it and then it will make sense.

Oh come on... and after this you say following:
C++ has awful syntax, according to my tastes.[/qote]
Get used to that, then it will make sense :) After that get used to Java and Cobol :)

[qupte]I commented because it seemed to me, like "Pseudonym73" was trying to blame the x87 for a C implementation bug. This isn't a problem with x87 or logic (assembly) but with not knowing what you are doing.
I think he meant it is easier to make mistakes with x87 by "not knowing" how it works, not because it is a bug with because of x87.
I just knew you was going to react to that :) That's why I added the "according to my taste".

But I guess after the terrible abomination of a rant I posted the other day, I deserve it. hehe.

What makes it "easy" to make bugs with the x87 is in my opinion this:

http://en.wikipedia.org/wiki/Floating_point
sol_hsa
I can't remember any architecture (at least x86 one) that had same circuit for floats and ints..

I might be thinking of a very old ARM or MIPS.

Kladdehelvete
This bug would be impossible to make in assembly, so to blame the x87 for what is a C implementation bug, just isn't right.

The x87 had no instruction to round a value to 64-bit or 32-bit precision; the only way to do it was to store to memory. So the only way to avoid this bug is to spill the register. This is a general feature of the x87 instruction set: you have a choice between wrong behaviour or slow behaviour.

To pick one far-from-random example, FDIV takes almost twice the time that DIVSS does on Sandy Bridge (24 cycles latency vs 14 cycles latency).

I don't know what division algorithm it uses, but it's probably a variant of the Goldschmidt algorithm. This is an iterative method which requires multiple trips through the multiply pipeline, but it requires fewer iterations if less precision is required. A 32-bit float requires less precision than an 80-bit float, so the instruction is much faster.