Floating-point inaccuracies permeate the game.
Moderator: ickputzdirwech
Floating-point inaccuracies permeate the game.
As you may know, a burner miner consumes 150 kW of energy to produce one mining operationg every 4 seconds.
Therefore, you might assume that using 600 kJ of energy, you should be able to yield one. Or more practially, that using 3 pieces of coal of 4 MJ each, or 12_000 kJ, a total of 20.
Here is what happens in practice.
There are countless, examples of this happening in nearly every calculation made by the game. Since the game is fixed at 60 UPS, is there any rational whatsoever in the liberal usage of floating-points in every aspects of what should essentially be integer math? I am not filling a bug-report since I already know this will be immediately disregarded as a "won't fix" or "minor" issue.
Therefore, you might assume that using 600 kJ of energy, you should be able to yield one. Or more practially, that using 3 pieces of coal of 4 MJ each, or 12_000 kJ, a total of 20.
Here is what happens in practice.
There are countless, examples of this happening in nearly every calculation made by the game. Since the game is fixed at 60 UPS, is there any rational whatsoever in the liberal usage of floating-points in every aspects of what should essentially be integer math? I am not filling a bug-report since I already know this will be immediately disregarded as a "won't fix" or "minor" issue.
Re: Floating-point inaccuracies permeate the game.
The game is not fixed at 60 ups, and machines may run faster or slower depending on beacons, modules, and available power. Functionally, these things don’t matter at scale - scale the game heavily encourages and incentivizes.
If you want to get ahold of me I'm almost always on Discord.
-
radical_larry
- Long Handed Inserter

- Posts: 95
- Joined: Wed Dec 04, 2024 1:52 am
- Contact:
Re: Floating-point inaccuracies permeate the game.
All those factors could still be accounted for in fixed point math. There's no point (ha) in using floating point math in a game engine that is fully deterministic.Rseding91 wrote: Fri Jun 26, 2026 10:03 pm The game is not fixed at 60 ups, and machines may run faster or slower depending on beacons, modules, and available power. Functionally, these things don’t matter at scale - scale the game heavily encourages and incentivizes.
I remember a time when Wube tried to program things correctly out of principle.
Re: Floating-point inaccuracies permeate the game.
This is essentially correct, floating-point arithmetic has a very specific use-case, it is also referred to as "scientific computation", because it's supposed to be used when dealing with the analogical measurement of natual phenomena, that is, using sensors of varying degrees of accuracy, that can be estimated to be within error intervals, where the innate inaccuracy of floating-points are meant to be a strict bound for this degree of noise, ie. half-precision (16-bits), full-precision (32-bits), double precision (64-bits), etc. while providing a sufficient dynamic range to remain equally (in relative terms) accurate at small and large scales.radical_larry wrote: Fri Jun 26, 2026 10:16 pmAll those factors could still be accounted for in fixed point math. There's no point (ha) in using floating point math in a game engine that is fully deterministic.Rseding91 wrote: Fri Jun 26, 2026 10:03 pm The game is not fixed at 60 ups, and machines may run faster or slower depending on beacons, modules, and available power. Functionally, these things don’t matter at scale - scale the game heavily encourages and incentivizes.
I remember a time when Wube tried to program things correctly out of principle.
You don't need floating-points to draw a circle using discrete pixels, or to calculate PI within an arbitrary degree of precision, which is how every CAS operates.
Re: Floating-point inaccuracies permeate the game.
Huh, I'm surprised to see this, I never noticed! I guess I expected that this problem would be magic-ed away somewhere in the background.
I'm not sure if the post author is making this assumption, but: integer division isn't necessarily faster than floating point division. Actually, I think it's usually the case that integer division is the slower operation. Given the importance placed on performance and the ubiquity of such math in the running of the game, it's the clear choice, right?
I'm not sure if the post author is making this assumption, but: integer division isn't necessarily faster than floating point division. Actually, I think it's usually the case that integer division is the slower operation. Given the importance placed on performance and the ubiquity of such math in the running of the game, it's the clear choice, right?
I'm not sure how the game being deterministic is relevant.radical_larry wrote: Fri Jun 26, 2026 10:16 pmAll those factors could still be accounted for in fixed point math. There's no point (ha) in using floating point math in a game engine that is fully deterministic.Rseding91 wrote: Fri Jun 26, 2026 10:03 pm The game is not fixed at 60 ups, and machines may run faster or slower depending on beacons, modules, and available power. Functionally, these things don’t matter at scale - scale the game heavily encourages and incentivizes.
I remember a time when Wube tried to program things correctly out of principle.
Re: Floating-point inaccuracies permeate the game.
I just took a quick look, and according to https://deepwiki.com/arturbac/fixed_mat ... ting-point it appears that fixed point (not integer) calculations are generally as good or better than floating point calculations.zwickau wrote: Fri Jun 26, 2026 11:05 pm Huh, I'm surprised to see this, I never noticed! I guess I expected that this problem would be magic-ed away somewhere in the background.
I'm not sure if the post author is making this assumption, but: integer division isn't necessarily faster than floating point division. Actually, I think it's usually the case that integer division is the slower operation. Given the importance placed on performance and the ubiquity of such math in the running of the game, it's the clear choice, right?
I'm not sure how the game being deterministic is relevant.radical_larry wrote: Fri Jun 26, 2026 10:16 pmAll those factors could still be accounted for in fixed point math. There's no point (ha) in using floating point math in a game engine that is fully deterministic.Rseding91 wrote: Fri Jun 26, 2026 10:03 pm The game is not fixed at 60 ups, and machines may run faster or slower depending on beacons, modules, and available power. Functionally, these things don’t matter at scale - scale the game heavily encourages and incentivizes.
I remember a time when Wube tried to program things correctly out of principle.
Re: Floating-point inaccuracies permeate the game.
Sounds like a drop-in replacement for the float type that could be used strategically for entity processing time (division) and status effect calculations (multiplication) with no loss of precision nor performance, but which would only give exact results. Do they care enough to try? This requires at least C++ 17.Khaylain wrote: Sat Jun 27, 2026 1:12 am I just took a quick look, and according to https://deepwiki.com/arturbac/fixed_mat ... ting-point it appears that fixed point (not integer) calculations are generally as good or better than floating point calculations.
https://github.com/arturbac/fixed_math
Another solution would be to use the (C++ built-in) integer division operator /= with a fixed resolution, just like is currently used for quality effects, for example using integers shown as multiples of 0.00001 for display, since factorio is a 64-bit game the loss in dynamic range would not be significant. There are many ways to go about solving this.
https://arturbac.github.io/fixed_math/division.html
Decimal floating-points would also work.
It's also fair to mention that binary floating-points (having no practical use-case in the game), is usually non-deterministic across CPUs, and might even be a cause for desyncs.
Re: Floating-point inaccuracies permeate the game.
Are you just going to bury this issue even after practical solutions have been provided to you? None of the concerns you stated are technically relevant, and I don't even see what you mean by UPS not being fixed since 1 second of in-game time is always 60 ticks, no matter the game.speed or how fast your computer runs.Rseding91 wrote: Fri Jun 26, 2026 10:03 pm The game is not fixed at 60 ups, and machines may run faster or slower depending on beacons, modules, and available power. Functionally, these things don’t matter at scale - scale the game heavily encourages and incentivizes.
Re: Floating-point inaccuracies permeate the game.
There is also the very specific use-case of high-performance calculation, since CPUs have the floating-point logic built-in and often have a more robust suite of operations for efficiently working on floating-point values.dupraz wrote: Fri Jun 26, 2026 10:27 pmThis is essentially correct, floating-point arithmetic has a very specific use-case,
I've done work with high-performance integer calculations, and have seen situations where it's actually faster to use the CPU's floating-point logic (carefully managed so that floating point error doesn't occur, or doesn't affect the end result) rather than its integer logic for the exact same sequence of operations.
Re: Floating-point inaccuracies permeate the game.
Even if that's the case, it would be a hack based on a quirk of the state of current CPU designs, which isn't even currently implemented correctly, considering the discrepancies in the results are clearly visible.Hurkyl wrote: Sat Jun 27, 2026 7:15 pmThere is also the very specific use-case of high-performance calculation, since CPUs have the floating-point logic built-in and often have a more robust suite of operations for efficiently working on floating-point values.dupraz wrote: Fri Jun 26, 2026 10:27 pmThis is essentially correct, floating-point arithmetic has a very specific use-case,
I've done work with high-performance integer calculations, and have seen situations where it's actually faster to use the CPU's floating-point logic (carefully managed so that floating point error doesn't occur, or doesn't affect the end result) rather than its integer logic for the exact same sequence of operations.
I don't even see how you would ensure consistency without rounding (which can be expensive), or somehow making sure you're only making divisions over whole binary values, since floating point operations produce an irreversible loss of information, which compounds.
See solutions like NTT.
Re: Floating-point inaccuracies permeate the game.
I don't agree.
There is a thing called "productivity", and another thing called "circuit-controlled recipe". When these two things come together, inaccuracies matter.
Because productivity bar can also stuck at 99% when it should give a bonus craft.
In theory, this is the only chance to switch recipe without losing productivity.
But in practice, if productivity bar is stuck at 99% , switching recipe will lose the maximum possible amount of productivity.
Re: Floating-point inaccuracies permeate the game.
Simple fixed point wouldn't help much either, what would - working on rational numbers in p/q format, both p and q being integers, but it may quickly overflow int64 unless everything is rescaled to sort of base-60 representation so instead of seconds time things are represented in ticks.
Re: Floating-point inaccuracies permeate the game.
This is exactly how "fixed-point" works. The library linked is a "48.16" implementation, meaning 48 bits for p (including 1 for parity), and 16 for q.Harkonnen wrote: Sat Jun 27, 2026 9:09 pm working on rational numbers in p/q format, both p and q being integers
Re: Floating-point inaccuracies permeate the game.
I mean that initial values should map directly to that that kind of representation, but we have things like 0.1sec all over the place. Not only that 0.1 does not have finite base-2 representation, 1/60 of it wouldn't either both base-2 and base-10, so the only reasonable way to go is fixed point, but on ticks (1/60sec), and that's quite an overhaul for in how many places this is currently used. One way to go though while technically staying at floats is to resnap it back to 1/60 grid after every +-*/, e.g. v = floor(v*60е8+0.5)/60e8dupraz wrote: Sat Jun 27, 2026 9:57 pmThis is exactly how "fixed-point" works. The library linked is a "48.16" implementation, meaning 48 bits for p (including 1 for parity), and 16 for q.Harkonnen wrote: Sat Jun 27, 2026 9:09 pm working on rational numbers in p/q format, both p and q being integers
P.S: Etymologically the word "second" comes from "second minute", so Factorio ticks deserve their place in vocabulary as the "third"
Re: Floating-point inaccuracies permeate the game.
Again, this is exactly how the /= operator works, and what is effectively being used for quality effects already, which is stored as an integer at a fixed resolution, which is then divided "for display purposes", only issue is that the resolution it was fixed at before 2.1 was... 1/10, which was not even accurate for even the most basic calculations. No idea why this wasn't the default approach.Harkonnen wrote: Sun Jun 28, 2026 12:34 am One way to go though while technically staying at floats is to resnap it back to 1/60 grid after every +-*/, e.g. v = floor(v*60е8+0.5)/60e8
I can't stress enough that floating-points are wildly inadequate for the simple reason that the innacuracy in absolute terms increases at high values to the point it quickly skips entire whole values (up to over 2^31 for a single step), the entire point being to allow for a greater dynamic range (say 2^127 instead of 2^31 for 32-bit), not higher precision.
Factorio doesn't need to store values up to 2^1024 (FP-64), not even 2^64 in fact, so it can afford to simply use these extra digits for decimal places (say 5 or 6), or rely on symbolic, fixed-point representations like any CAS.
Of course, that doesn't solve issues where the "ratios" being calculated by the game are neither able to be represented by decimal nor binary numbers, like the current Heat exchangers (1/97, prime denominator, which is admitedly silly), but then again, whether the inaccuracy is down to 6 decimal places, or 31, in these edge cases, makes little difference.
See also
Re: Floating-point inaccuracies permeate the game.
You've misunderstood something.dupraz wrote: Sat Jun 27, 2026 9:57 pmThis is exactly how "fixed-point" works. The library linked is a "48.16" implementation, meaning 48 bits for p (including 1 for parity), and 16 for q.Harkonnen wrote: Sat Jun 27, 2026 9:09 pm working on rational numbers in p/q format, both p and q being integers
48.16 means that when you write out numbers in binary notation, there are always 16 places to the right of the point and 48 places to the left of the point. (thus, the position of the point is "fixed")
That corresponds to q being hard-coded to the constant 65536 in the rational number format. (and p being a 64 bit integer)
Re: Floating-point inaccuracies permeate the game.
My point being, it's functionally equivalent to the manual integer-divided-for-display approach, except more convenient and predictable. Also p cannot be 64-bits since p and q must fit within 64-bits in the first place.Hurkyl wrote: Sun Jun 28, 2026 8:34 am 48.16 means that when you write out numbers in binary notation, there are always 16 places to the right of the point and 48 places to the left of the point. (thus, the position of the point is "fixed")
That corresponds to q being hard-coded to the constant 65536 in the rational number format. (and p being a 64 bit integer)
The only real solution for non-decimal values would be a true rational type, or simply designing the game to avoid these awkward values, which is fairly easy considering how most effect calculations are multiplications based on decimal representations. Problem would be values like 1/3, see how quality purposefully avoids them by using the a fixed 0.3 scaling factor instead? They literally figured out the solution by themselves then dropped it. Same problem as the heat exchanger design, once someone figured out how to do things that made sense, but then someone else did something completely differently, which results in these incomprehensible inconsistencies across the game. A general solution would be, obviously, to use a greater base-system which is a multiple of every base functionally necessary, 60 was mentioned, since it's a multiple of 2, 3, 10, etc. (30 would work just as well) but base 97 (which is currently used for Heat exchangers) would just not be acceptable unless you use rational types or something like base 223_092_870.
Going back to my simple burner miner example, here, progress is made by steps equal to 150/60, which is 2.5 J per tick, which should be able to be represented both with binary and decimal, even if it's floating-point instead of fixed-point, so what is going on here?
Last edited by dupraz on Sun Jun 28, 2026 9:38 pm, edited 1 time in total.
-
Panzerknacker
- Filter Inserter

- Posts: 377
- Joined: Mon Aug 22, 2022 5:27 am
- Contact:
Re: Floating-point inaccuracies permeate the game.
I think u newbz should show some respect to the devs which made the game like this probably for a good reason. If u don't like it play another game. They aint gonna change fundamental stuff like this at this point.
Re: Floating-point inaccuracies permeate the game.
There really isn't, using floating-points is not faster, and is simply less accurate, they probably defaulted to this without thinking much about it, then realized the problem by themselves while designing quality, changed the approach mid-way, and now the game has 2 conflicting approaches running concurrently (also known as an internal contradiction), one is accurate but (artificially) limited, the other is innacurate. It's fair to say the "performance hit" of using even full-blown rational types for every calculation would not be so significant since it only needs to be made when entity properties are being modified, not every tick (which can be cached, and probably already is).Panzerknacker wrote: Sun Jun 28, 2026 9:37 pm the devs which made the game like this probably for a good reason.
Re: Floating-point inaccuracies permeate the game.
q requires zero bits of storage; it's hard-coded.dupraz wrote: Sun Jun 28, 2026 9:09 pmMy point being, it's functionally equivalent to the manual integer-divided-for-display approach, except more convenient and predictable. Also p cannot be 64-bits since p and q must fit within 64-bits in the first place.Hurkyl wrote: Sun Jun 28, 2026 8:34 am 48.16 means that when you write out numbers in binary notation, there are always 16 places to the right of the point and 48 places to the left of the point. (thus, the position of the point is "fixed")
That corresponds to q being hard-coded to the constant 65536 in the rational number format. (and p being a 64 bit integer)
That's the point of a fixed-point data type: it's functionally identical to floating-point representations, but you don't have to use any bits to store the exponent part because you fix it to a constant (in this case to -16) and never change it. So you get a 64 bit significand rather than the 53 bit significand of the standard 64-bit floating point type which is great if you're in the range where you have enough precision and aren't wasting too much. (and the fixed exponent helps if you have to do a software implementation using integer types)
You're missing the point that there are other, relatively arbitrary multipliers on things like power usage. For example, brownouts can throttle energy usage by an amount depending on the available and required power. Modules can change the energy usage too, which can again be fairly arbitrarily scaled if the beacon they're in is partially powered.A general solution would be, obviously, to use a greater base-system which is a multiple of every base functionally necessary, you mentioned 60, since it's a multiple of 2, 3, 10, etc. (30 would work just as well) but base 97 (which is currently used for Heat exchangers) would just not be acceptable unless you use rational types or something like base 223_092_870.
I'm betting that there's an off-by-one error in expectations. Like, if you turn it on at tick zero, your burner miner outputs a coal at tick 240, 480, 720, and so forth.Going back to my simple burner miner example, here, progress is made by steps equal to 150/60, which is 2.5 J per tick, which should be able to be represented both with binary and decimal, so what is going on here?
Then if you supply the burner miner with exactly 600 kJ of energy, it will power the miner through ticks 0-239, and when tick 240 comes there is no fuel left, so the miner doesn't output its item because it's unpowered.


