Skip to content

Commit 0406cf4

Browse files
committed
VM_rint: do not generate negative zeroes when the input is positive.
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.
1 parent e4b0b90 commit 0406cf4

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

prvm_cmds.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,10 +1511,22 @@ void VM_rint(prvm_prog_t *prog)
15111511
VM_SAFEPARMCOUNT(1,VM_rint);
15121512

15131513
f = PRVM_G_FLOAT(OFS_PARM0);
1514-
if (f > 0)
1515-
PRVM_G_FLOAT(OFS_RETURN) = floor(f + 0.5);
1514+
// Guarantee that integers (including negative zeroes) and infinities
1515+
// remain as is. This also guarantees the following code doesn't run
1516+
// for zeroes.
1517+
if (f == floor(f))
1518+
PRVM_G_FLOAT(OFS_RETURN) = f;
1519+
// The copysign ensures that output negative zeroes always have the
1520+
// same sign as the input. This likely is already the case anyway,
1521+
// but I honestly can't find anywhere in the C standards which kind of
1522+
// zero floor(0.8) and ceil(-0.8) are supposed to be.
1523+
else if (f < 0)
1524+
PRVM_G_FLOAT(OFS_RETURN) = copysign(floor(f + 0.5), f);
15161525
else
1517-
PRVM_G_FLOAT(OFS_RETURN) = ceil(f - 0.5);
1526+
PRVM_G_FLOAT(OFS_RETURN) = copysign(ceil(f - 0.5), f);
1527+
// NOTE: Technically rint() when rounding to nearest should round
1528+
// towards even. Leaving things as is for now, though, as it matches
1529+
// Quake.
15181530
}
15191531

15201532
/*

0 commit comments

Comments
 (0)