It is possible to have `` a <b and not (ab <0) '' with floats
there is
a < b and not(a - b < 0)
is it possible for floating points due to a floating point error? Is there an example?
It depends on the floating point format and, in particular, whether it has a gradual overflow . IEEE 754 binary floating point. This means that the gap between two separate floats is always non-zero, even if it can only be represented by one significant bit in the extreme case.
The smallest possible absolute difference between two separate floats has an equal sign (or one of the numbers 0), a zero exponent and values different by 1. In this case, subtracting the larger from the smaller will result in the smallest negative number of the negative sign, zero and 1 This number is compared to less than zero.
There are other calculations that make the lower value zero. For example, dividing the smallest positive number by a number greater than or equal to two results in zero in the normal rounding mode.
[This answer is intended as an addition to pedants to the subtle answer already given by Patricia Shanahan. This answer covers the normal case; here we worry about extreme cases that you are unlikely to encounter in practice.]
Yes, it is quite possible. Here's a Python session from my most ordinary Intel Mac laptop:
Enthought Canopy Python 2.7.6 | 64-bit | (default, Jan 29 2014, 17:09:48) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import evil >>> a = float.fromhex('1p-1022') >>> b = float.fromhex('1.01p-1022') >>> a < b and not(a - b < 0) True Of course, as import shows, something happens there. Here is the content of evil.py (Warning: this is very platform specific, and, as written, it will only work on OS X. Variations on this should work on Linux / x64, provided that Python has been compiled to use SSE2 instructions instead of the x87 block for floating point operations don't have about windows.)
# Being lazy: we should really import just the things we need. from ctypes import * # Type corresponding to fenv_t from fenv.h. (Platform specific!) class fenv_t(Structure): _fields_ = [("control", c_ushort), ("status", c_ushort), ("mxcsr", c_uint), ("reserved", c_char * 8)] # Wrap fegetenv and fesetenv from the C library. libc = CDLL("/usr/lib/libc.dylib") fegetenv = libc.fegetenv fegetenv.restype, fegetenv.argtypes = c_int, (POINTER(fenv_t),) fesetenv = libc.fesetenv fesetenv.restype, fesetenv.argtypes = c_int, (POINTER(fenv_t),) # Set the flush-to-zero (FTZ) bit in the MXCSR control register. env = fenv_t() fegetenv(pointer(env)) env.mxcsr |= 1 << 15 fesetenv(pointer(env)) So, what we are doing here is fiddling with the FPU settings stored in the MXCSR control register. On Intel 64 processors that support SSE instruction sets, there are two interesting flags that affect the behavior of operations with subnormal numbers. The FTZ (flush-to-zero) flag, when set, causes any subnormal output of the arithmetic operation to be replaced with zero. The DAZ (denormals-is-zero) flag, when set, causes any abnormal input for an arithmetic operation, as if it were zero. The essence of these flags is that they can significantly speed up operations with subnormal numbers by reducing compliance with IEEE 754. In the above code, we set the FTZ flag in the MXCSR control register.
And now we choose a and b so that both a and b are normal, but their difference is subnormal. Then a < b will be true (as usual), but a - b will be -0.0 , and the comparison a - b < 0 will fail.
The departure point is that it is not enough that the floating point format is used in the IEEE 754. You also need to know that your actions are in compliance with the standard. FTZ mode is an example of how this can happen. To associate this with Patricia Shanahan, the answer is: the code in evil.py disables the gradual overflow, which IEEE 754 promises. (Thanks @EricPostpischil for pointing this out in the comments.)
You can easily run some of the “corner cases” as shown
>>> from itertools import product >>> for a, b in product([0.0, 1.0, float('-inf'), float('inf'), float('nan')], repeat=2): ... print a < b and not(a - b < 0)... False False # and so on