This commit is contained in:
Miloslav Ciz 2023-01-15 15:55:54 +01:00
parent 3361c59555
commit b5ab038925
4 changed files with 18 additions and 16 deletions

View file

@ -5,9 +5,9 @@ Fixed point arithmetic is a simple and often [good enough](good_enough.md) metho
Fixed point has at least these advantages over floating point:
- **It doesn't require a special hardware coprocessor** for efficient execution and so doesn't introduce a [dependency](dependency.md). Programs using floating point will run extremely slowly on systems without float hardware support as they have to emulate the complex hardware in software, while fixed point will run just as fast as integer arithmetic. For this reason fixed point is very often used in [embedded](embedded.md) computers.
- It is **easier to understand and better predictable**, less tricky, [KISS](kiss.md), [suckless](sukless.md). (Float's IEEE 754 standard is 58 pages long, the paper *What Every Computer Scientist Should Know About Floating-Point Arithmetic* has 48 pages.)
- It is **natural, easier to understand and therefore better predictable**, less tricky, [KISS](kiss.md), [suckless](sukless.md). (Float's IEEE 754 standard is 58 pages long, the paper *What Every Computer Scientist Should Know About Floating-Point Arithmetic* has 48 pages.)
- Is easier to implement and so **supported in many more systems**. Any language or format supporting integers also supports fixed point.
- Isn't ugly and **doesn't waste values** (unlike IEEE 754 with positive and negative zero, denormalized numbers, many [NaNs](nan.md) etc.).
- Isn't ugly and in [two's complement](twos_complement.md) **doesn't waste values** (unlike IEEE 754 with positive and negative zero, denormalized numbers, many [NaNs](nan.md) etc.).
## How It Works
@ -25,6 +25,8 @@ in our system has to be normalized like this:
(`000010.00` * `000000.10`) / 4 = `000001.00` (2.0 * 0.5 = 1.0)
SIDE NOTE: in practice you may see division replaced by the shift operator (instead of `/4` you'll see `>> 2`).
With this normalization we also have to **think about how to bracket expressions to prevent rounding errors and [overflows](overflow.md)**, for example instead of `(x / y) * 4` we may want to write `(x * 4) / y`; imagine e.g. *x* being `00000010` (0.5) and *y* being `00000100` (1.0), the former would result in 0 (incorrect, rounding error) while the latter correctly results in 0.5. The bracketing depends on what values you expect to be in the variables so it can't really be done automatically by a compiler or library (well, it might probably be somehow handled at [runtime](runtime.md), but of course, that will be slower). There are also ways to prevent overflows e.g. with clever [bit hacks](bit_hack.md).
The normalization is basically the only thing you have to think about, apart from this everything works as with integers. Remember that **this all also works with negative number in [two's complement](twos_complement.md)**, so you can use a signed integer type without any extra trouble.