Naive ways to compute a fractional part f of a float number x rely on the computation of either _, f = divmod(x, 1.0)
or f = x % 1.0
. This works well for many numbers, but not for all. For instance:
x = -math.ulp(0.49999999999999994)
(k, f) = divmod(x, 1.0) # k = -1.0 and f = 1.0
The computation is correct and divmod
does its job as advertised, under the constraints of inexact computations inherent to the finite representation of numbers. But f fails to be the fractional part of x because mathematicians do not allow a genuine fractional part to take the value 1.0. Thus, the vanilla flavor of either divmod or % is not the right tool when one desires to compute a fractional part.
Hand-Made Solution 1
f = (x % 1.0) % 1.0
k = round(x - f)
Hand-Made Solution 2 (Patch)
(k, f) = divmod(x, 1.0)
if 1.0 == f:
f -= math.ulp(1.0)
Hand-Made Solution 3 (One attempt to be accurate)
Remark: math.ulp(1.0) / 2.0 != math.ulp(0.49999999999999994)
(k, f) = (0.0, 0.0)
if x <= -math.ulp(1.0):
(k, f) = divmod(x, 1.0)
elif x < -math.ulp(1.0) / 2.0:
(k, f) = (-1.0, 1.0 - math.ulp(1.0))
elif x < 0.0:
(k, f) = (0.0, 0.0)
else:
(k, f) = divmod(x, 1.0)
Does a native Python function exist that returns a genuine fractional part in the spirit of the hand-made approaches above?