Reputation: 746
I've been reading the paper What Every Computer Scientist Should Know About Floating-Point Arithmetic.
I have seen various ULP calculations and felt I pretty much understood it until the discussion of subtraction came up.
Take another example: 10.1 - 9.93. This
becomes
x = 1.01 × 10^1
y = 0.99 × 10^1
x - y = .02 × 10^1
The correct answer is .17, so the computed difference is off by 30 ulps
and is wrong in every digit!
Why is this 30ulps and not 0.3? Because surely the ulp is 0.01x10^1, or in other words 0.1. The error is 0.03, which is 0.3 ulps.
Upvotes: 7
Views: 1448
Reputation: 3354
the ULP is now the smallest value in this normalized representation: 0.01 × 10^-1.
What some answers don't highlight, is that ULP is relative to the approximated value.
It is not the smallest representable number, but the difference between best lower and upper approximations of the given number.
Let me rework this example in two ways:
a)
The exact result of .17
satisfies these optimal, within precision of 3, bounds:
0.01 x 10^1 <= .17 <= 0.02 x 10^1
hence the ULP equals
ULP(0.17) = 0.02 x 10^1 - 0.01 x 10^1 = 0.01 x 10^1 = 0.1
and consequently, the error is
0.02x10^1-0.17 = 0.03 = 30 ULP
b)
You can also use this fact from the paper
In general, if the floating-point number d.d...d × 10^e is used to represent z, then it is in error by |d.d...d - (z/10^e)| x 10^(p-1) units in the last place
Since we approximate 0.17=1.7x10^-1
with 0.2=2x10^-1
the result gives us
|1.7-2|x10^2 ULP = 30 ULP.
NOTE: Usually, we abbreviate ULP(x)
to ULP
for the sake of brevity.
Upvotes: 0
Reputation: 3955
The correct answer is written in the comments but I'll write it down as an answer so that it's not hidden in the comment noise.
Basically x - y = .02 × 10^1
gets normalized to 2.00 × 10^-1
, and this means that the ULP is now the smallest value in this normalized representation: 0.01 × 10^-1
.
Consequently the error is
0.03 / [(0.01 × 10^-1)/ULP] = 30 ULP
Upvotes: 3