The answer is yes, with the qualifications that:
- float & int are the same size.
- inputs are positive, float values that don't include:
-0.0
, -inf
, nan
, -nan
.
Details:
- Both
signed int
and unsigned int
can be used with matching comparisons.
- Assumes IEEE754 32bit floating point.
- Both int & float need to be the same endian (do architectures exist where this is not the case?)
- Not just
0-1
, 0.0..FLT_MAX
and inf
can be compared.
- For completeness, negative values:
-0.0..-FLT_MAX
can be compared too but will always have a flipped order, eg:
assert(float_as_int(a) > float_as_int(b) == a < b);
In this case, 2x floats represented as ints can be compared, giving the same results.
Here is a evidence that this can work:
C code, tests the full, unsigned float range.
#include <math.h>
#include <float.h>
#include <stdio.h>
int main() {
unsigned step = 0;
union {
float f;
unsigned u;
} value;
value.f = 0.0;
unsigned u_prev = value.u;
while (value.f != FLT_MAX) {
value.f = nextafterf(value.f, FLT_MAX);
unsigned u = value.u;
if (u <= u_prev) {
printf("At value %f, step %u, comparisons don't match\n", value.f, step);
break;
}
u_prev = u;
step++;
}
printf("Tested %u times\n", step);
return 0;
}
a Python3 script, checking all values from 0-1 with nextafterf
, note that this is slow (hence the C version above).
def main():
from struct import pack, unpack
as_u32_prev = None
value = 0.0
while True:
# transmute float to int
as_u32 = unpack('I', pack('f', value))
if as_u32_prev is not None:
if as_u32_prev > as_u32:
raise Exception("f32/u32 comparisons don't match")
as_u32_prev = as_u32
if value == 1.0:
break
value = nextafterf(value, 1.0)
# Boiler Plate, see: https://stackoverflow.com/questions/6063755
import ctypes
import sys
from sys import platform as _platform
if _platform == "linux" or _platform == "linux2":
_libm = ctypes.cdll.LoadLibrary('libm.so.6')
_funcname_f = 'nextafterf'
elif _platform == "darwin":
_libm = ctypes.cdll.LoadLibrary('libSystem.dylib')
_funcname_f = 'nextafterf'
elif _platform == "win32":
_libm = ctypes.cdll.LoadLibrary('msvcrt.dll')
_funcname_f = '_nextafterf'
else:
# these are the ones I have access to...
# fill in library and function name for your system math dll
print("Platform", repr(_platform), "is not supported")
sys.exit(0)
nextafterf = getattr(_libm, _funcname_f)
nextafterf.restype = ctypes.c_float
nextafterf.argtypes = [ctypes.c_float, ctypes.c_float]
main()
Note that other answers here say that this wont work in all cases,
I'd be interested to know which cases the examples in this answer would fail, (besides architectures where float and int aren't 4 bytes in size).