I’ve got a NEON register filled with float32. I’d like to round them to the nearest integer without having to transfer back to the main CPU. The NEON instructions to convert float32 to uint32 simply truncate, so e.g. 39.7 becomes 39, not 40. I don’t care much about how 0.5 gets handled — round away from zero or round to even both work for me.
The best path I can see to implement rounding is to
- convert to
int32(thus truncating) - convert back to
float32 - add 1 to the
int32, convert back tofloat32, and set aside in case we’re rounding up - subtract
- compare to
0.5(no need for abs value since I know in my case they’ll all be positive) - select truncated or truncated + 1 based on the comparison outcome
That seems ugly, slow, and complicated.
Is there a cleaner, faster, simpler, saner way?
Add .5 and convert to integer. If you want the result in floating-point format, convert back.
Since you know the numbers are all positive, another option is to add 0x1p23 and subtract 0x1p23. The result of adding 0x1p23 is at least 0x1p23, so the float result has no bits with value less than one, so it must have been rounded to an integer. Then subtracting 0x1p23 subtracts the value that was added, leaving only the effect of rounding.
Update: This second method fails if the input is in [0x1p47, 0x1p48) and its low bit is one. Then 0x1p23 is half the ULP of the input, so the addition causes rounding upward (to even), and the subtraction has no effect. I think there is a modification to fix that, but I do not have it at hand.