Skip to content

Commit

Permalink
Add explanation of converting between floating and fixed point (#21)
Browse files Browse the repository at this point in the history
* Add explanation of converting between floating  and fixed point

This is useful in many situations, like when generating fixed point
constants, or when printing fixed point values for debugging (or non
debugging) purposes.

Also, fix some qualifiers (`extern` isn't needed, `const` is nice to
use).

* Update content/fixed-point-math.md

Co-authored-by: Antonio Vivace <avivace4@gmail.com>

* Add suggestion

---------

Co-authored-by: Antonio Vivace <avivace4@gmail.com>
  • Loading branch information
AntonioND and avivace committed Mar 24, 2024
1 parent 0a9eafc commit 4b37aed
Showing 1 changed file with 54 additions and 5 deletions.
59 changes: 54 additions & 5 deletions content/fixed-point-math.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,13 @@ Let's say we have a player sprite, with an X and Y position. What speed should w

```c
// a function elsewhere in code, which needs the ONSCREEN x and y position
extern void display_player(int x, int y);
void display_player(int x, int y);

// player coordinates use signed 28.3f fixed-point format
int player_fp = 3;
const int player_fp = 3;

// 1 and 5/8, written verbosely for demonstration purposes
int player_speed = 8 + 5;
int player_speed = (1 << player_fp) + ((5 << player_fp) / 8);

// let's start the player at (5, 6) on the screen
// shift both of these values left to account for the fixed-point
Expand Down Expand Up @@ -163,10 +163,11 @@ Before adding or subtracting fixed-point numbers, you need to make the denominat

```c
// variable 'a' uses an unsigned 27.5f fixed-point format
int a_fp = 5;
const int a_fp = 5;
unsigned int a = 3 << a_fp;

// variable 'b' uses an unsigned 16.16f fixed-point format
int b_fp = 16;
const int b_fp = 16;
unsigned int b = 4 << b_fp;
```

Expand Down Expand Up @@ -206,6 +207,54 @@ Even though you can't do hardware-level division, there are usually creative wor

If you really must divide, you would multiply the numerator by the fixed-point first, *before* dividing.

## Converting between fixed and floating point

Now you have a way to do mathematical operations efficiently. How do you set the initial values in a convenient way? How do you print the values in a way that is easier to understand than very big integer values?

Well, you can convert between fixed and floating point easily:

```c
const int player_fp = 3;

static inline int player_float2fixed(float value)
{
return (int)(value * (1 << player_fp));
}

static inline float player_fixed2float(int value)
{
return value / (float)(1 << player_fp);
}

// Macro version of the functions, for situations where you can't use functions
#define PLAYER_FLOAT2FIXED(value) (int)((value) * (1 << (player_fp)))
#define PLAYER_FIXED2FLOAT(value) ((value) / (float)(1 << (player_fp)))

int setup(void)
{
int player_x = player_float2fixed(1.23);
int player_y = PLAYER_FLOAT2FIXED(2.35);

printf("Player X: %f\n", player_fixed2float(player_x);
printf("Player Y: %f\n", PLAYER_FIXED2FLOAT(player_y);
}
```
Remember that those are floating point operations, so they will be slow. There is an exception: if you use `constexpr` or if the compiler detects that an expression is constant, it will calculate it at compile time automatically. This is very useful for setting initial fixed point values from floating point values.
```c
int player_x, player_y;
constexpr int player_start_x = player_float2fixed(1.23); // Only in C++
const int player_start_y = PLAYER_FLOAT2FIXED(2.35);
int setup(void)
{
player_x = player_start_x;
player_y = player_start_y;
}
```

And there you go! You now know everything needed to do fixed-point math. Good luck!

## FAQ
Expand Down

0 comments on commit 4b37aed

Please sign in to comment.