Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add explanation of converting between floating and fixed point #21

Merged
merged 3 commits into from
Mar 24, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this bitwise expanded a bit? Like shift 1 by 3 position will effectively multiply 1 for 2^3 and same for the 5/8

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct: 1 << 3 is 8, so the first part of the addition is correct. The second one is just 5 * 8 / 8, but at least this way it's more clear that the intention is to have 5/8 in fixed point, rather than just a random 5.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe I've misunderstood your suggestion.

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I wasn't discussing the correctness, just to expand a bit more explaining the shift

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean, but I'm not sure how to change the explanation to make it more clear. I think that the shift itself doesn't need to be understood as a multiplication, more like "making room for decimals".

In any case, if the rest of the PR is ok, we can merge it and that can be improved later, all I wanted with this change is explain a bit better where "5" was coming from, and now it's just using the general formula for any number, so...


// 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

Okay, so 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?
AntonioND marked this conversation as resolved.
Show resolved Hide resolved

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 the operations 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.
AntonioND marked this conversation as resolved.
Show resolved Hide resolved

```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