# Calculating ULP distance between two floating point numbers (quickly)

**URL:** <https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581>\
**Category:** General Usage\
**Tags:** float\
**Created:** [May 21, 2021, 11:48am UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581 "2021-05-21T11:48:19Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![fellbyyourgun](https://avatars.discourse-cdn.com/v4/letter/f/d07c76/32.png) [@fellbyyourgun](https://discourse.julialang.org/u/fellbyyourgun)\
**Post date:** [May 21, 2021, 11:48am UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581/1 "2021-05-21T11:48:19Z")

</div>

I need to compare floating point numbers for near-equality. I would like to compare them based on the ULP distance (see [here](https://bitbashing.io/comparing-floats.html) if you aren’t familiar/need a refresher).

The most straightforward way to do this, as far as I know, is to convert the bits that make up the floating point numbers into their equivalent integers, and then take the difference of the two resulting integers as the ULP distance.

The very naive solution I have come up with is to do something like this in Julia is:

```julia
function ULPsBetween(a::Float64, b::Float64)
    a = bitstring(a)
    b = bitstring(b)
    
    aintegerrepresentation = parse(Int, a; base=2)
    bintegerrepresentation = parse(Int, b; base=2)
    
    return aintegerrepresentation - bintegerrepresentation
end

```

This code works correctly, but it’s very slow since it calls bitstring() and parse(). I used BenchmarkTools to evaluate the performance, and its on the order of 1 microsecond. For the number of times this function will be called in my program, that is very slow.

In C, we can do something like this instead of the parse() function:

```julia
int64_t floatToInt(double f)
{
    int64_t r;
    memcpy(&r, &f, sizeof(double));
    return r;
}

```

This code executes on the order of a few nanoseconds.

Obviously, I’m not using Julia correctly. But what would a more elegant/faster solution look like? Any ideas?

For now, I will probably write a Julia function that calls the C code above with ccall(). But I would really prefer to have everything in pure Julia. Finally, I searched quite a bit and couldn’t find anything about calculating the ULP distance in Julia on here or StackOverflow, so this post may be useful to others who find themselves in the same situation in the future.

Thank you!

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [May 21, 2021, 12:08pm UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581/2 "2021-05-21T12:08:37Z")

</div>

Either use `reinterpret` to convert your floats to integers and extract the bit patterns from that or rescale the output of `significand` or `frexp`.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 21, 2021, 12:26pm UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581/3 "2021-05-21T12:26:17Z")

</div>

> [@fellbyyourgun](#):
>
> I need to compare floating point numbers for near-equality.

Is using `isapprox` an option? You can give it an absolute or relative allowed difference.

In case it isn’t, the code from your link would look like this in julia:

```julia
function ulpsBetween(a::Float64, b::Float64)
    a == b && return 0
    isnan(a) || isnan(b) && return typemax(Int)
    isinf(a) || isinf(b) && return typemax(Int)
    
    a_int = reinterpret(Int64, a)
    b_int = reinterpret(Int64, b)

    (a_int < 0) != (b_int < 0) && return typemax(Int)

    return abs(a_int - b_int)
end

```

Still, the link discusses precisely why this sort of comparison usually isn’t a good idea (and `isapprox` is usually the best choice anyway). It’s implemented like this:

```julia
function isapprox(x::Number, y::Number;                                                                                          
                  atol::Real=0, rtol::Real=rtoldefault(x,y,atol),                                                                
                  nans::Bool=false, norm::Function=abs)                                                                          
    x == y || (isfinite(x) && isfinite(y) && norm(x-y) <= max(atol, rtol*max(norm(x), norm(y)))) || (nans && isnan(x) && isnan(y)
end                                                                                                                              

```

which you can find via `@edit isapprox(0.5, 1.0)` at `base/floatfuncs.jl:360`.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 21, 2021, 12:32pm UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581/4 "2021-05-21T12:32:30Z")

</div>

Like @GunnarFarneback suggested, something like this?

```julia
ulpdistance(a, b) = -(reinterpret.(Int, (b, a))...)

```

Could make it a bit less terse, maybe… Runtime is a couple of ns.

Hm, I see that @Sukera wrote something similar, it looked totally different at first glance.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 21, 2021, 12:33pm UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581/5 "2021-05-21T12:33:52Z")

</div>

That approach ignores special handling `NaN` and `Inf` though.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 21, 2021, 12:36pm UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581/6 "2021-05-21T12:36:31Z")

</div>

Yeah, yeah, boring 😉

---

<div class="post-metadata">

**Author:** ![fellbyyourgun](https://avatars.discourse-cdn.com/v4/letter/f/d07c76/32.png) [@fellbyyourgun](https://discourse.julialang.org/u/fellbyyourgun)\
**Post date:** [May 21, 2021, 12:37pm UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581/7 "2021-05-21T12:37:05Z")

</div>

Wow, I wasn’t expecting such excellent answers so quickly! What a great community. I’m glad I adopted Julia for this project.

reinterpret() was exactly what I needed.

I will look into using isapprox() instead of the ULP method.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 21, 2021, 12:40pm UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581/8 "2021-05-21T12:40:41Z")

</div>

If what you _actually_ want is approximate comparison of floats, then that’s exactly what `isapprox` is for.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [May 21, 2021, 3:09pm UTC](https://discourse.julialang.org/t/calculating-ulp-distance-between-two-floating-point-numbers-quickly/61581/9 "2021-05-21T15:09:59Z")

</div>

It seems to me that a more reliable way than comparing integer representations (which won’t work if the two numbers are more than a factor of two apart) would be just to use `(b - a) / eps(a)`:

```julia
julia> a, b = 1.1, nextfloat(1.1)
(1.1, 1.1000000000000003)

julia> (b - a) / eps(a)
1.0

```
