Rounding Errors

From Townstons

Why doesn't my math come up with the same value as in the Character Sheet?

Two possibilities:

  • Non-floating Point Math
  • Frame Rate Considerations


Contents

Non-Floating Point Math

This due in large part from the fact that Dungeon Runners can not use floating point math. In particular, fractional numbers are not expressed as decimals.

Stephen has stated on this forum post that:


The problem stems from the fact that we can't use floating point math in our game logic. So, we use a fixed point system based on 24 bits for the whole number and 8 bits for the fraction.


In essence the largest whole number in 24-bit binary is: 2 24 - 1 = 16777215

The fraction is expressed in 8-bit binary in increments of: 2 -8 = 1 / 256

It is this fraction that causes "rounding errors". Decimal fractions displayed in game, on the Character Sheet for example, are actually values rounded FROM the nearest 1 / 256 increment.


For example:

0.63 as a displayed decimal could have been rounded from the following 8-bit fractions:
160/256,  161/256  or 162/256  (0.625, 0.62891 or 0.63281).


All calculations would be performed using 24-bit whole numbers and 8-bit fractions. The final results would also be in 24-bit whole numbers and 8-bit fractions. When the final results or any other number is to be displayed in-game, that is when it gets rounded and converted to a decimal.


Calculation Examples

The following will illustrate where rounding errors can occur.


Decimal Calculation

Let's take for instance a Final Attack Speed Calculation:

Bad Mutha: Ranged Attack Speed = 0.63
Trigger Happy Passive = +25% Ranged Attack Speed
Max Rank Trigger Finger Frenzy = +115% Ranged Attack Speed

Final Attack Speed = 
(
Base Attack Speed
( 1 + %attk spd bonus )
)
 
(
0.63
( 1 + 0.25 + 1.15 )
)
 
Final Attack Speed =  0.2625
 
Displayed Character Sheet    
Final Attack Speed =  0.27

As can be seen, the final result is 0.2625. When this is displayed as a 2-place decimal it DOES NOT round to the 0.27 displayed on the Character Sheet.

As can be seen from the above, there is a rounding error that could be attributed to the 8-bit fraction, which will be shown in the following section.


8-bit Fraction Calculation

Using the same example,
Bad Mutha: Ranged Attack Speed = 0.63
Trigger Happy Passive = +25% Ranged Attack Speed
Max Rank Trigger Finger Frenzy = +115% Ranged Attack Speed

First determine what 8-bit fractions could have
been used to round up to the displayed values (see table to right):

      
Rounded Decimal
Fraction
Possible 8-bit Fractions Decimal Equivalents
0.63 160/256, 161/256, 162/256 0.625, 0.62891, 0.63281
0.25 64/256 0.25
1.15 1 38/256, 1 39/256 1.14844, 1.15234

Keeping in mind that all fractional values are calculated and stored as 8-bit fractions.
What is actually displayed in game is a rounded value of those 8-bit fractions.

Final Attack Speed = 
(
Base Attack Speed
( 1 + %attk spd bonus )
)
 
(
0.63281
( 1 + 0.25 + 1.14844 )
)
 
Final Attack Speed =  0.26384
 
Final Attack Speed (8-bit Fraction) =  68/256 (rounded to nearest 1/256 fraction)
 
Final Attack Speed (8-bit Fraction) =  0.26563 as the decimal equivalent.
 
Displayed Character Sheet    
Final Attack Speed =  0.27

As can be seen, the final result is 68/256. When this is displayed as a 2-place decimal it DOES round to the 0.27 displayed on the Character Sheet.


Sometimes, 2 + 3 ≠ 5

Displayed
Percentage
Rounded Decimal
Fraction
Possible 8-bit Fractions Decimal Equivalents
2% 0.02 4/256,  5/256,  6/256 0.01562,  0.01953,  0.02343
3% 0.03 7/256,  8/256 0.02734,  0.03125
5% 0.05 12/256,  13/256,  14/256 0.04688,  0.05078,  0.05469

Before deciding if you want to equip that 5% item
or two items at 2% and 3%, respectively; consider the the table to the right:


It may be possible that:

  • the 2% item may have been rounded from 4/256
  • the 3% item may have been rounded from 7/256.

When added together, the result is 11/256 or 0.04297

...which rounds to 4% and not 5% !!!


Basically, wear the item(s) and check your Character Sheet for a change.

Particularly, wear the item(s) and check your Character Sheet when they are of a higher level than before!
The rounding error may work in your favor with the next level of item instead of against you!
Displayed values of 2% and 3% may actually add up to 5% with higher level items!


Things to remember

  • The math may be done with 8-bit fractionals first. It is suspected that the original numbers and the results are also stored in this format.
  • When the the results or original numbers are displayed in game, they may be rounded from the 8-bit fractionals.
  • Sometimes, 2% + 3% ≠ 5


Frame Rate Constraints

The other source of "rounding errors" could be a result of frame rate considerations.

A video game is basically a computer controlled animation. The illusion of movement is shown by animating a series of frames depicting objects in succesive positions. The rate that the frames are displayed is known as FPS or Frames per Second. As benchmarks, movies are generally displayed at 24 FPS, video is displayed at 30 FPS (interlaced) and HD can be at 60 FPS (progessive). The more frames that can be used to represent a movement, the more "fluid" the movement appears.

In PC games a target frame rate for game animation could be around 60 FPS. On older, less capable systems or when there is lag, the frame rate may bog down to 30 FPS. This lower frame rate could appear as choppy movements or slo-motion movements for a game designed for 60 FPS.

The "tiered" rounding effect may be a result of some imposed framerate constraints.


Tiered Rounding

The tiered rounding effect could be a result of avoiding a split frame result. Since you can't have a half frame, the smallest time increment you can depict is 1/60 or 0.017 seconds.
And hey lets face it, there may be some spot lag or boggy systems out there, so designing for 30 FPS will drive the smallets depictable time increment to 1/30 or 0.033 seconds.

When rounding attack speed, the game may be designed to round to the nearest (laggy/boggy) frame... or every 0.033 attacks/second.