Skip to content

Conversation

@divVerent
Copy link
Contributor

This new rint() now returns always matches output sign to input.

It should match C23's round() perfectly, but is explicit about the handling of negative zeroes in input and output and still keeps the original Quake logic for safety.

@divVerent divVerent force-pushed the divVerent/fix-rint branch 3 times, most recently from ffd3c83 to 0406cf4 Compare August 15, 2025 14:53
@divVerent
Copy link
Contributor Author

@uis246 Comparison for test values with all deltas from C's rint function highlighted:

input rintf roundf rint_q1 rint_dpold rint_dpnew
-3e+09 -3e+09 -3e+09 ! -2.14748365e+09 ! -3e+09 -3e+09
-2.14748365e+09 -2.14748365e+09 -2.14748365e+09 -2.14748365e+09 -2.14748365e+09 -2.14748365e+09
-16777218 -16777218 -16777218 -16777218 -16777218 -16777218
-16777216 -16777216 -16777216 -16777216 -16777216 -16777216
-16777215 -16777215 -16777215 -16777215 -16777215 -16777215
-16777214 -16777214 -16777214 -16777214 -16777214 -16777214
-8388609 -8388609 -8388609 -8388609 -8388609 -8388609
-8388608 -8388608 -8388608 -8388608 -8388608 -8388608
-8388607.5 -8388608 -8388608 -8388608 -8388608 -8388608
-8388607 -8388607 -8388607 -8388607 -8388607 -8388607
-1.6 -2 -2 -2 -2 -2
-1.5 -2 -2 -2 -2 -2
-1.4 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-0.6 -1 -1 -1 -1 -1
-0.5 -0 ! -1 ! ! -1 ! ! -1 ! ! -1 !
-0.4 -0 -0 ! 0 ! -0 -0
-0 -0 -0 ! 0 ! -0 -0
0 0 0 0 ! -0 ! 0
0.4 0 0 0 0 0
0.5 0 ! 1 ! ! 1 ! ! 1 ! ! 1 !
0.6 1 1 1 1 1
1 1 1 1 1 1
1.4 1 1 1 1 1
1.5 2 2 2 2 2
1.6 2 2 2 2 2
8388607 8388607 8388607 8388607 8388607 8388607
8388607.5 8388608 8388608 8388608 8388608 8388608
8388608 8388608 8388608 8388608 8388608 8388608
8388609 8388609 8388609 8388609 8388609 8388609
16777214 16777214 16777214 16777214 16777214 16777214
16777215 16777215 16777215 16777215 16777215 16777215
16777216 16777216 16777216 16777216 16777216 16777216
16777218 16777218 16777218 16777218 16777218 16777218
2.14748365e+09 2.14748365e+09 2.14748365e+09 ! -2.14748365e+09 ! 2.14748365e+09 2.14748365e+09
3e+09 3e+09 3e+09 ! -2.14748365e+09 ! 3e+09 3e+09

It actually matches roundf exactly on x86, but is explicit about things not cleared up in the standard. It in particular fixes the negative zero DP outputs when fed exactly 0. Let's consider this the best possible compromise between Quake and ISO C.

https://godbolt.org/z/z9a59ev96

@divVerent
Copy link
Contributor Author

divVerent commented Aug 16, 2025

BTW, DP's change to rint came here:

commit 757a7dcbb67fcbeac0275a072dd984fd15a96b93
Author: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date:   Sat Aug 26 07:02:49 2006 +0000

    CSQC fixes (less broken, still not spec compliant)
    CSQC can now link the same entity multiple times (each time modified differently) as per the CSQC spec (this is mainly useful for rendering multi-model players based on one csqc entity, like Quake3's cgame does)
    changed DrawQ functions to automatically set up 2D rendering if previous rendering was of a 3D view (necessary change for proper CSQC support)
    changed QuakeC rint builtin implementation to handle very large values (outside of int range) and possibly run a little bit faster, note that it still rounds toward the nearest integer, away from zero (as intended)
    refactored gun bob, damage kick fade, and stair smoothing code to eliminate a 'multiple fade steps per frame' bug
    renamed the misnamed VM_ftoi function to VM_ftoe, in accordance with the menu QC builtin ftoe
    
    
    git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6568 d7cf8633-e32d-0410-b094-e92efae38249

So the goal of DP's change in 2006 was specifically to avoid the undefined behavior (which on x86 usually returns -2.14748365e+09, and on ARM usually saturates).

@Cloudwalk9
Copy link
Contributor

Cloudwalk9 commented Aug 25, 2025

I'm averse to changing the behavior of this to anything other than stock Quake, which obviously DP's version is not stock apparently, for compatibility reasons, because it involves floating point, and to give an example, last time we had 64 bit QCVM, there were so many codepaths with downcasting bugs that I had to turn it off until they were fixed in normal builds, and it caused so many subtle bugs in map logic.

But if this doesn't break entity logic, timing, etc, and is more correct, sure. Do buttons return to their original position when pushed? Do elevators randomly kill you or just not work? Do doors close? Do monsters seem to act weird(er than they already do in DP)?

@divVerent
Copy link
Contributor Author

divVerent commented Aug 26, 2025 via email

@divVerent
Copy link
Contributor Author

divVerent commented Aug 26, 2025

Put it behind a gameplayfix, that defaults to 1, and on 0 replicates the old broken Quake behavior.

@divVerent divVerent force-pushed the divVerent/fix-rint branch 2 times, most recently from 8cf50bd to 0da6063 Compare August 26, 2025 19:33
This matches what rint() does by default in all current compilers, but
does not depend on rounding mode.

NOTE: VM_rint from Quake is _not_ rint from the C standard; it does not
round to _even_ when breaking ties. It actually is C23's roundeven().

Fixes issue #276.
@divVerent
Copy link
Contributor Author

Any news here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants