This function is the factor \(1 / B\) smaller cousin of
find_ulp_of_one_plus
,
which you can refer to for more elaboration of the fine points.
We start with the value \(2 / 3\), which rounds in any
radix not a multiple of \(3\). It's bigger than one-half,
so it lies in the exponent range just below 1.0
in any of radix 2, 8, 10, or 16.
Following the earlier discussion, \(2 / 3\) has the
decimal value
\(0.6666\cdots\) and the binary value
\(0.101010\cdots _{2}\).
Analogous to the case of \(4 / 3\),
the value TWO / THREE
evaluates to \(2/3 + \epsilon\).
The rounding error \(\epsilon\) is
\(+1 / 3, +4 / 3, +7 / 3, \ldots\)
or \(-2 / 3, -5 / 3, -8 / 3, \ldots\)
ulps of values just less than 1.0
.
We then isolate and triple \(\epsilon\) by computing \[ | (1/6 + \epsilon) + ((1/6 + \epsilon) \times 2) - 1/2) | \] which reduces to \[ | (1/6 + \epsilon) + (-1/6 + 2\epsilon) | \] all in exact arithmetic. As in the cousin function, it simplifies to \( | 3 \epsilon |\).
Here is a binary diagram showing the case of odd precision.
The value \(1 / 6\) is subtracted out, leaving a whole number
of ulps of values just less than 1.0
, regardless
of the radix.
def find_ulp_of_one_minus(guess):
"""Compute u such at 1-u is the next smaller value than 1."""
x = TWO / THREE
sixth = x - ONE_HALF
third = sixth + sixth
x = third - ONE_HALF
x = fabs(x + sixth)
if (x < guess):
x = guess
# Now x == (unknown no.) ulps of 1-.
Exercise: Replay the binary case with even
precision to see that
it also proudces an ulp of 1.0
.
Exercise: The diagram below starts the computation in 6-digit decimal arithmetic.
Can you complete the computation of x
?
Exercise: This diagram
illustrates the computation of x
in 6-digit octal arithmetic. We assume chopped arithmetic,
as found on Burroughs computers of the 1960s.
Now rerun the computation in 7-digit octal.