I am aware that when I type x = 2.1, for example, x is not necessarily the number I typed. It would be the number I typed only if the number I typed were exactly representable as a floating point number. Please correct me if I am wrong!
That is exactly correct. For example, x = 2.5
is exactly representable.
If I want an interval containing 2.1, I understand that I can use
y = 2.1…2.1
and this will make sure 2.1 in within my interval.
Correct.
Now my question is, if I have a floating point number, x = 2.1 for example, then what exactly
y = x…x
does? How does it guarantee that 2.1 is in this interval? Does it take the interval [x1, x2], where x1 is the largest representable number smaller than x and x2 is the smallest representable number larger than x? If this is the case then I can see that 2.1 would be contained in x…x.
This is almost correct. What it does is form an Interval
using the following two numbers:
julia 0.6> (prevfloat(x), nextfloat(x))
(2.0999999999999996, 2.1000000000000005)
That is, one below and one above the floating-point number x
.
In previous versions of the package, it tried to be more clever, by e.g. converting x
to a rational first:
julia 0.6> rationalize(x)
21//10
julia 0.6> convert(Interval{Float64}, rationalize(x))
Interval(2.0999999999999996, 2.1)
This literally does do what you suggested; however, it is much slower. The version using prevfloat
only loses one “ulp”, i.e. it is one floating-point number wider.
However, if this is the case, the width of the interval I obtain with 2.1…2.1 could be larger than needed when the number I type is exactly representable. Is there a way to type a number a and get the thin interval [a, a] if a is exactly representable and get an interval containing a if a is not exactly representable?
You can do the following, but it is quite slow:
julia 0.6> x = 2.1; s = string(x)
"2.1"
julia 0.6> Interval(parse(Float64, s, RoundDown), parse(Float64, s, RoundUp))
Interval(2.0999999999999996, 2.1)
julia 0.6> x = 2.5; s = string(x)
"2.5"
julia 0.6> Interval(parse(Float64, s, RoundDown), parse(Float64, s, RoundUp))
Interval(2.5, 2.5)