August 20th, 2024

Neo Geo Dev: Fixed Point Numbers

The article explains fixed point numbers for the Neo Geo, enabling decimal-like calculations using integers. It discusses their advantages, drawbacks, and practical coding examples for game development, emphasizing precision management.

Read original articleLink Icon
Neo Geo Dev: Fixed Point Numbers

The article discusses the implementation of fixed point numbers in programming for the Neo Geo, a vintage gaming console that lacks native support for decimal numbers. Unlike modern computers that utilize floating point arithmetic for decimal calculations, the Neo Geo operates solely with integers. To work around this limitation, developers can use a fixed point system, where the decimal point's position is predetermined, allowing for fractional values while still using integer arithmetic. The article explains the advantages of fixed point systems, such as speed and simplicity, as well as their drawbacks, including limited precision and flexibility. It emphasizes the importance of fixed point numbers in game development, particularly for sprite movement, where fractional pixel movement can enhance gameplay fluidity. The author provides a basic framework for creating a fixed point system, including macros for conversion and functions for multiplication and division, while also addressing potential overflow issues. The article concludes with a discussion on the need for precision adjustments in fixed point systems as game development progresses.

- Fixed point numbers allow for decimal-like calculations on systems that only support integers.

- The Neo Geo uses fixed point arithmetic to manage sprite movement and other calculations requiring fractional values.

- Developers must carefully choose the number of bits allocated for integer and decimal parts in fixed point systems to balance precision and range.

- Overflow management is crucial when performing arithmetic operations with fixed point numbers.

- The article provides practical coding examples for implementing fixed point arithmetic in game development.

Link Icon 15 comments
By @nritchie - 8 months
When I was a freshman (or so) in high-school, our computer lab had just graduated from a time-share terminal to the next-door university to the Apple II. A kid (Ray Tobey) in the next grade up started to code a project to submit to a Byte Magazine game contest. The due date came and went, but he carried on in every moment of his free time. Long story short, this game became SkyFox of which Woz said "consider this flight simulator as the finest Apple game ever done." From Ray, I learned the value of using continued fraction approximations to trig functions using only integer math. Later, this became useful when I had to implement image rotation in a scan generator for a scanning electron microscope.
By @BearOso - 8 months
Multiplying without having a larger intermediate is much more complex than the article states. You have to use the commutative property of multiplication and split the whole and decimal parts of each number out, otherwise you're stuck with single digit whole numbers or only multiplying fractions.

So you'd take

  A.a * B.b and split it into A*B + A*b + a*B + a*b
Or

    out = ((A >> fixedbits) * (B >> fixedbits) << fixedbits)
        + ((A >> fixedbits) * b)
        + ((B >> fixedbits) * a)
        + ((a * b) >> fixedbits);
If you can get away with a little less precision and smaller whole numbers, you can avoid some of the multiplications by just doing this, which is quite common:

    (A.a >> (fixedbits / 2)) * (B.b >> (fixedbits / 2))
By @wk_end - 8 months
I always felt when learning about this stuff that people - pedagogically - make fixed point seem more complicated than it is.

Since this article is talking about more precisely positioning sprites in a 2D world, it could practically be a one-liner: "instead of tracking positions/velocities in pixels, track them in half pixels". Everything falls out of that intuition.

By @fidotron - 8 months
It's worth saying the original Playstation was entirely fixed point. You can go surprisingly far with it.

https://en.wikipedia.org/wiki/Fixed-point_arithmetic#Softwar...

I spent so much of the early stage of my career doing early mobile stuff I practically still think in fixed point, and always have to adjust to floats, for example, fixed point results can be compared exactly while with floats that is not a great idea. TeX uses fixed point entirely because it was reproducible across machines in an era where floating point was not.

By @capitainenemo - 8 months
Hedgewars uses fixed point due to inconsistencies in floating point implementations breaking deterministic lockstep. 0AD and Spring: RTS has similar issues although I think both use streflop now.
By @mmaniac - 8 months
This sort of thing is ordinary for consoles without floating point numbers. It's easy to do in software with integers, but sometimes hardware acceleration will use it too.

The SNES and GBA both supported affine transformations, where the elements of the multiplication matrix are fixed point numbers. The Playstation's geometry coprocessor (GTE) used fixed point matrices with quite low 16 bit precision. An emulator feature called PGXP is able to perform these calculations at higher precision.

By @vardump - 8 months
On the PC side, most developers stopped predominantly using fixed point for high performance code somewhere in the Pentium 1-3 era. For 486 class systems it was still pretty useful.

Other than on retro systems, fixed point is still useful in smaller microcontrollers.

By @tralarpa - 8 months
On the Amiga and Atari, based on the Motorial 68000 like the NeoGeo, all 3D games used fixed point arithmetic.

At that time, such games were written in assembler, and you had to be very careful to place the instructions for scaling and descaling in the right places, not only to get the final result in the right units (i.e., screen coordinates), but also in intermediate calculations to preserve precision.

By @fizzynut - 8 months
Is it possible to get rid of all the macros TO_FIXED, FROM_FIXED, mult, etc and replace them with a class with the correct constructors / operator overloads?

Then your code doesn't ever need to be aware of the special fixed point math and horrible syntax everywhere and everything just works?

By @jnwatson - 8 months
FYI, the multiply assert isn't guaranteed to work and can be compiled out by a sufficiently smart compiler. Overflow of signed values is UB, the compiler can assume that UB is impossible, therefore the expression in the if resolves to false.
By @teo_zero - 8 months
When I see a snippet like this

  int temp = a * b;
  ngassert(
        abs(temp) >= abs(a),
        "overflow!"
  );
I wonder what stops the compiler from optimizing away the assert, as it's clearly based on an undefined behavior.
By @throwawayk7h - 8 months
Fixed point should really be used way more often than it is. It's much safer, for one thing, and less mysterious. But because C lacks first-class support for fixed point, the whole world has become flopsy.
By @pjmlp - 8 months
Besides all the given examples, this was also quite common in J2ME games, given the limitations of the environment, and hardware differences across phones.
By @djmips - 8 months
Nit to the author. Decimal point. Decimal digits. Actually binary point and binary digits.
By @adancalderon - 8 months
"If you wan't"