I'm betting a FixedPoint package will be created early on (either by me or someone else :smile: ). The reason for this is that fixed point has a number of advantages:
A drawback with fixed point though is that it doesn't have as large a range of representable values compared to floating point. Typically a fixed point number is represented with 64 bits. Some number of bits represent the integer part, 1 bit for the sign, and the rest represent the fractional part.
My question is, of those 63 bits (1 bit is used already for the sign), how much should be used for the integer part and how much should be used for the fractional part?
Some ideas:
Anyone else have any thoughts on this?
Edit: There could of course be multiple FixedPoint types with different trade-offs between range and precision but I think it would be best if there's a single FixedPoint type so the user doesn't have to convert between different types all the time.
Dec is fixed point! :smiley:
it's 128-bit fixed point specifically
Dec is base 10 right? You are correct that it's fixed point, but I guess when I hear fixed point I assume base 2. My bad for the confusion :sweat_smile:
base 10 indeed!
the goal is to make it the default non-integer type, so if you put 0.1 + 0.2 into the repl, it evaluates it as a Dec and gives you 0.3
My use case is a number type that's fast enough to be suitable for physics engines but also deterministic so that it's suitable for peer to peer multiplayer games. I don't think Dec fits that use case? At least to me it seems like using 128 bits and working with base 10 will cause a significant performance loss (again, within the context of physics engines, its performance is probably fine for most applications).
ah, so I suppose base 2 would be faster
so as I understand it, floating point numbers can be that as long as you're using the same trigonometry functions
this is based on a conversation with Mason Remaley awhile back
my understanding is that IEEE-754 defines precisely enough how floating point operations ought to work that every CPU gives the same answer for the same hardware instructions
however, for some reason the trig functions (sin, cos, etc) are actually slower in hardware than when done in software with lookup tables
so it's normal to use userspace trig functions from libc, and sometimes those software implementations give different answers on different machines
if all of this is correct, then Roc could get deterministic floating-point operations across machines by not using the local libc, and rather providing our own software implementations for trig functions in the roc stdlib
I think that would be the absolute fastest, in the sense that I don't think even base-2 fixed point can be faster than floating point except maybe at addition, subtraction, multiplication, and division
since addition and subtraction can be hardware integer ops, which are generally faster than hardware floating point ops, and multiplication and division in base 2 can be bit shifts, which should be significantly faster than hardware floating point multiplication and division especially
that said, I don't know about fixed-point sqrt and trig
they certainly don't have hardware support, but if floating point wants to use lookup tables anyway, maybe you just do fixed-point lookup tables and end up getting equivalent performance anyway? I'm not sure!
My understanding about floating point determinism is largely based on this article https://randomascii.wordpress.com/2013/07/16/floating-point-determinism/. In the article the author mentions
Rounding, precision, exceptions, and denormal support – that’s a lot of [CPU] flags. If you do need to change any of these flags then be sure to restore them promptly. Luckily these settings should rarely be altered so just asserting once per frame that they are as expected (on all threads!) should be enough. There have been sordid situations where floating-point settings can be altered based on what printer you have installed and whether you have used it. If you find somebody who is altering your floating-point settings then it is very important to expose and shame them.
though I guess the platform can check if these CPU flags are consistent between platforms?
There's other things that get mentioned like (a + b) + c where some CPUs can store the a + b in a temporary register with higher precision before adding c which would lead to a different result. I admit I don't really understand the details on when this happens.
There's a lot of stuff in the article and maybe it can all be addressed but it does make me want to just write my own FixedPoint package to make sure that the results really are deterministic and a multiplayer game isn't going to desync with an extremely difficult to pin down bug.
yeah the platform can set those flags once and then not change them :thumbs_up:
that said, it should be possible to write your own fixedpoint type in pure Roc that has the same performance as if it were written in C/C++/Rust/etc
we expose all the hardware primitives with no overhead, e.g. Num.addWrap is just a single addition instruction
Richard Feldman said:
yeah the platform can set those flags once and then not change them :thumbs_up:
The article seems to say that those CPU flags can be changed at any point and as a result the platform would need to check on each thread, repeatedly while the program is running. Maybe that's overkill and printers aren't so badly programmed anymore but it does make me a little nervous.
well certainly the Roc compiler won't emit any instructions that change them, and the Roc stdlib doesn't change them either :big_smile:
so if they changed, it's because the platform ran some code that changed them
Maybe I'm just mistaken but it seems like device drivers (maybe other normal programs?) all share and modify the same floating point CPU flags? The article is 9 years old so maybe things have changed as well.
oh interesting - like if the OS is doing time slices and doesn't restore the flags after switching back to your process after running another one
now I understand what you mean about threads - not just your own code, but other processes' code too
yeah I guess that could happen!
I work on an online multiplayer multiplatform physics game. Just wanted to concur that trying to get perfect float determinism on all platforms may theoretically be possible but would be a ton of work. We settle for close enough using quantization. I think a fast fixed-point math library would be fantastic.
Last updated: Jun 16 2026 at 16:19 UTC