libfixmath does Q16.16 fixed point maths without needing a floating point unit
Cross Platform Fixed Point Maths Library
At a glance
- What is it?
- libfixmath is a C library of fixed point operations in the Q16.16 format, aimed at microcontrollers where a floating point unit is expensive or absent, and it is shaped almost entirely by compile time defines. Seven options trade speed against accuracy, switch off the static caches, remove the hardware division requirement, and adjust the code for 8-bit processors, but the README states plainly that the project is not actively maintained.
- Who is it for?
- Adopt libfixmath if you are writing firmware for a processor without a floating point unit and you need trigonometry, exponentials and fixed point arithmetic with predictable behaviour and no external dependency.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 102 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Fixed point as a way to avoid the floating point unit
libfixmath implements Q16.16 format fixed point operations in C, and the reason it exists is the hardware, not the mathematics.
On a microcontroller with no floating point unit, every float operation is a software routine, and for a control loop that runs on a timer that is the difference between meeting a deadline and missing it. A Q16.16 number stores a signed 32 bit value where the top 16 bits are the integer part and the bottom 16 bits are the fraction, which gives roughly three and a half decimal digits of precision and, importantly, arithmetic that is integer arithmetic, so it is fast and bit exact and the same code produces the same results on every target.
The audience is firmware developers who have decided that fixed point is the right trade for their processor. That is a real decision with real costs, and the library is designed to be used after you have made it rather than as a way of avoiding the decision.
The repository layout backs up the scope. There is libfixmath/ for the library itself, fixsingen/ for the sine generator, fixtest/ for the test program, benchmarks/ for the benchmark code, an images/ directory, and an AUTHORS file and a library.json manifest. The presence of fixsingen as a separate directory is the tell that the trigonometry is generated rather than hand written, which is how a fixed point sine table of a usable accuracy is produced at all.
The project is MIT licensed, with the licence named in the README and a LICENSE file at the repository root, and the primary language is C. The default branch is master, the repository is not archived, and the last push was on 2026-07-13.
Seven compile time defines decide what the library becomes
The options section is the real documentation for this library, and its shape is unusual. Configuration is done with compile definitions checked by the preprocessor with #ifdef and #ifndef, and all of them are undefined by default, so the default build is the most capable one and the defines are opt in for constrained targets.
The list covers the whole range of embedded compromises. FIXMATH_FAST_SIN switches the sine implementation. FIXMATH_NO_64BIT is for compilers and platforms that have no uint64_t. FIXMATH_NO_CACHE turns off the static memory caches. FIXMATH_NO_HARD_DIVISION is for platforms with no hardware integer division. FIXMATH_NO_OVERFLOW turns off the overflow check. FIXMATH_NO_ROUNDING turns off rounding. FIXMATH_OPTIMIZE_8BIT tunes the code for processors with 8-bit multiplication such as Atmel AVR.
Two of these have knock on effects that are easy to miss. FIXMATH_OPTIMIZE_8BIT also defines FIXMATH_NO_HARD_DIVISION automatically in fix16.h, so the 8-bit path gives up the hardware division as well. And FIXMATH_NO_HARD_DIVISION is noted as being automatically defined if FIXMATH_OPTIMIZE_8BIT is defined, which is the same fact stated in the other direction.
The overflow and rounding options are the ones that change results rather than speed. With FIXMATH_NO_OVERFLOW undefined, the library checks for overflow and returns the overflow constants instead of a wrapped value, and with FIXMATH_NO_ROUNDING undefined it rounds. Both of those have numerical consequences, and a user who sets them for speed is changing the arithmetic, not just the implementation.
The fast sine trades two tenths of a percent of accuracy for speed
The FIXMATH_FAST_SIN option is the one with a number attached, and the numbers are worth reading side by side because they define the trade precisely.
Without the define, you get the most accurate version, accurate to about 2.1 percent. With it, you get the fast implementation, which runs at 159 percent the speed of the accurate version with a slightly lower accuracy of about 2.3 percent.
So the fast path is roughly one and a half times faster and gives up two tenths of a percentage point of accuracy. Whether that is a good trade depends entirely on your application, which is why it is a compile time option rather than a runtime setting. A trigonometric function with an error of two percent is fine for a smoothing filter and useless for a measurement that has to be right to a tenth of a degree, and the library is not in a position to make that call for you.
There is also a structural reason the two versions exist. A fixed point sine cannot call the C library's sin, because the C library works in floating point, so the library has to carry its own implementation, and on a microcontroller with no FPU a good one is expensive in cycles. That is presumably why the trigonometry is generated by the fixsingen tool, and why there is a trigonometry cache at all, which is the subject of the next section.
The accuracy figures are also a reminder of what a Q16.16 library can promise. Two percent is a coarse instrument by the standards of a desktop double, and the reason to accept it is that it runs where a double cannot.
The caches cost 112KB of static memory, and you can turn them off
The FIXMATH_NO_CACHE option decides whether the library keeps its lookup tables in static memory, and the sizes are stated.
Without the define, the library uses static memory caches for exponents, 32KB, and for trigonometry, 80KB. With the define, it does not use caches.
That is a large amount of RAM for a microcontroller, and it is the option that most often decides whether the library is usable on a small part. A part with 8KB of RAM cannot have the caches, a part with 256KB can, and a part with 20KB is in the awkward middle where the user has to work out which side of the line they are on.
The caches exist because the fixed point implementations of exponential and trigonometric functions need lookup tables, and a table lookup is fast while a polynomial evaluation is not, particularly on an 8-bit multiplier. The two caches are separate because they serve different functions, and the 80KB trigonometry cache is the one that dominates.
There is a tension between the two options that is worth naming. FIXMATH_NO_CACHE saves 112KB of RAM and costs you the speed that the tables bought, while FIXMATH_FAST_SIN buys speed back with accuracy. On a part that has to use both defines, you end up with the fastest and least accurate build of the library, which is a legitimate configuration for something like a motor controller and a poor one for anything that measures.
The static nature of the caches also has an implication for concurrency that the README does not discuss, and it is worth being aware of: they are static memory, so two threads calling into the library at once are writing to the same tables.
CMake FetchContent is the supported way to depend on it
The README gives one integration path, and it is the modern CMake one.
The simplest way to use libfixmath as a dependency is with CMake's FetchContent API, and the snippet is complete enough to copy:
include(FetchContent)
FetchContent_Declare(
libfixmath
GIT_REPOSITORY https://github.com/PetteriAimonen/libfixmath.git
GIT_TAG <the long git hash of the version you want>
)
FetchContent_MakeAvailable(libfixmath)Two details in that snippet are deliberate. The tag is a long git hash rather than a branch or a tag name, which is the reproducible dependency practice, and it makes sense here for a project with no releases. And the compile definitions are passed to the target afterwards, with the option names listed as comments so you can see at a glance what is available:
target_compile_definitions(libfixmath PRIVATE
# FIXMATH_FAST_SIN
# FIXMATH_NO_64BIT
# FIXMATH_NO_CACHE
# FIXMATH_NO_HARD_DIVISION
# FIXMATH_NO_OVERFLOW
# FIXMATH_NO_ROUNDING
# FIXMATH_OPTIMIZE_8BIT
)Then the library is linked into the consuming target in the ordinary way, with target_link_libraries pointing at libfixmath. There is also a CMakeLists.txt at the root of the repository itself, and a library.json manifest, which is the file format used by PlatformIO, so a project that builds with PlatformIO has another route in.
The point of the options being compile definitions rather than runtime settings is that the library is meant to be specialised at build time for a specific target. FetchContent makes that natural, since the definitions are set on the target rather than globally.
A mirror of a Google Code SVN repository, and a project that says it is not maintained
The first two lines of the README set the history and the status, and both matter for anyone deciding to depend on it.
This is a mirror of the libfixmath's original SVN repository on Google Code. So the canonical history of the project lives in an SVN repository hosted by a service that Google has wound down, and what is on GitHub is a copy. The repository carries an AUTHORS file, and the topic list includes no modern tooling beyond a .travis.yml for continuous integration and a .github/ directory.
The second line is the status, and it is stated in bold in the README: not actively maintained, pull requests welcome. The licence is MIT.
There is an interesting tension between those two facts and the quality of the library itself, and the honest way to write this article is to say both. A library that implements Q16.16 fixed point maths, ships a sine generator, has a benchmark directory, a test program and a CMake integration path is not the work of a weekend. The options list, with its measured speed and accuracy figures and its explicit memory budgets, reads like the result of someone tuning a library against real hardware constraints over a long period.
But the project says it is not maintained, and the README should be taken at its word. The relevant question for an adopter is therefore not whether the code is good, which it appears to be, but whether you are willing to own it. A 32 bit fixed point library with no floating point unit dependency is not a large surface area to maintain, and the changes it needs are rare, so the risk is less about bug fixes and more about a compiler or a toolchain change breaking a build.
On the licence metadata, there is a small inconsistency to note. The repository licence field records a custom licence that GitHub cannot classify, while the README states MIT and links to the MIT licence text, with a LICENSE file at the root. The README and the file are the authoritative statements.
When native floating point is the better answer
The honest alternative to a fixed point library is the C language's own float and double, and on a processor with a hardware floating point unit that is very often the better choice.
The difference in approach is where the rounding happens. With native floating point, the compiler and the hardware handle the precision, you get a much larger dynamic range than Q16.16 offers, and you get the accuracy of a double, which is many orders of magnitude better than the two percent the fixed point sine manages. The cost is the hardware itself, since a microcontroller with an FPU is a more expensive part, and on a part without one every float operation becomes a software call.
So the decision is a hardware decision that the library is designed to serve. If your processor has an FPU and your algorithm is not latency critical, using double is simpler, more accurate and less code. If your processor is an 8-bit or Cortex-M part without an FPU, or your control loop has a hard deadline, fixed point is the only option that meets the requirement, and libfixmath gives you trigonometry and exponentials with the arithmetic you have.
A third option is writing the fixed point routines yourself, which is what many embedded projects end up doing, and that is where this library's real value shows. The generated sine table, the overflow constants, the overflow checking and the rounding are all the parts that are tedious to get right and easy to get subtly wrong, and the FIXMATH_NO_OVERFLOW and FIXMATH_NO_ROUNDING defines let you choose whether you want those guarantees.
The limitation to keep in view is the accuracy ceiling. If your application needs a sine accurate to a thousandth of a degree, neither the fast nor the accurate path of this library is close, and a floating point implementation or a different design is the answer.
Editorial conclusion
Adopt libfixmath if you are writing firmware for a processor without a floating point unit and you need trigonometry, exponentials and fixed point arithmetic with predictable behaviour and no external dependency. Do not adopt it if your target has a usable FPU, because a compiler with hardware floating point will usually be simpler and more accurate, and do not adopt it expecting a maintained library, because the README says it is not actively maintained even though pull requests are welcome. Before you build with it, read the option list and decide which defines to set, since the cache options alone commit 32KB plus 80KB of static memory, and check the accuracy of the fast sine path against the accuracy your control loop actually needs.
Frequently asked questions
What is libfixmath and what format does it use?
It is a C library implementing Q16.16 format fixed point operations, intended for microcontrollers where a floating point unit is unavailable or expensive. The README lists the options as compile definitions checked with #ifdef and #ifndef, all undefined by default.
How much memory do the libfixmath caches use?
By default the library keeps static memory caches of 32KB for exponents and 80KB for trigonometry, 112KB in total. Defining FIXMATH_NO_CACHE turns the caches off.
What does FIXMATH_FAST_SIN change?
Without it you get the most accurate version at about 2.1 percent accuracy, and with it the fast implementation runs at 159 percent the speed with a slightly lower accuracy of about 2.3 percent. FIXMATH_OPTIMIZE_8BIT additionally defines FIXMATH_NO_HARD_DIVISION automatically in fix16.h.
How do I add libfixmath to a CMake project?
The README recommends CMake's FetchContent API, declaring the repository with a long git hash as the tag, calling FetchContent_MakeAvailable, setting any FIXMATH compile definitions on the target and linking the libfixmath target.
Is libfixmath still maintained?
The README states it is not actively maintained, while saying pull requests are welcome. The repository is a mirror of the original SVN repository on Google Code, and the last push was on 2026-07-13.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/petteriaimonen-libfixmath)Was this useful?