Public Interface

Types

PrecisionCarriers.PrecisionCarrierType
PrecisionCarrier{AbstractFloat}

A carrier type for floating points. Most math functions are overloaded for this type. Initialize it with some value (or see precify to convert an entire array or tuple type of numbers), do some arithmetic with your value(s), and finally, print it to check the number of accumulated epsilons of error.

julia> using PrecisionCarriers

julia> function unstable(x, N)
           y = abs(x)
           for i in 1:N y = sqrt(y) end
           w = y
           for i in 1:N w = w^2 end
           return w
       end
unstable (generic function with 1 method)

julia> unstable(precify(2), 5)
1.9999999999999964 <ε=8>

julia> unstable(precify(2), 10)
2.0000000000000235 <ε=53>

julia> unstable(precify(2), 20)
2.0000000001573586 <ε=354340>

julia> unstable(precify(2), 128)
1.0 <ε=4503599627370496>
Note

A precision carrier of BigFloat is allowed, but is mostly useful for functions that only use it intermediately. Using a carrier of BigFloat as input for a function will simply result in always 0 ε error reported. Also note that in this case, epsilons is not implemented, because BigFloat does not have a type epsilon.

source

Macros

PrecisionCarriers.@bench_epsilonsMacro
@bench_epsilons(call_expr, args...)

Benchmark the epsilons of a given function call.

The first argument should be a function call, with variables from local context interpolated, and arguments that should be sampled defined in a ranges = begin ... end block. In the ranges block, every variable must be assigned a Tuple of a lower and an upper bound for values that should be sampled.

using PrecisionCarriers

foo(x, y) = sqrt(x^2 - y^2)

@bench_epsilons foo(1.0, y) ranges = begin
    y = (0.5, 1.0)
end samples = 1000 epsilon_limit = 10

Returned is an object containing information about the benchmark results that can be displayed to a terminal similar to BenchmarkTools' @benchmark.

Supported keyword arguments:

  • search_method: How the sampling should be done. Supported are:
    • :pseudo_random: Create pseudo-random sample points in the search space using Sobol.jl.
    • :evenly_spaced: Creates an evenly spaced grid across all ranges
    • :random: Randomly samples points in the given ranges.
    The default is :pseudo_random.
  • samples: The number of samples taken. Default: 10000
  • epsilon_limit: Results with epsilons larger than this will be stored together with the arguments that produced the imprecise result. Default: 1000
  • keep_n_values: Maximum number of imprecise results that will be stored.
source

Functions

PrecisionCarriers.precifyFunction
precify([::Type{PrecisionCarrier{T}}], t::Any) where {T<:AbstractFloat}
precify([::Type{T}], t::Any) where {T<:AbstractFloat}

Convert a number or container to a container of PrecisionCarriers. If no specific float type for the PrecisionCarrier is specified, the type of ts floats will be used.

julia> using PrecisionCarriers

julia> precify((0, 1.0, 2.0f0))
(0.0 <ε=0>, 1.0 <ε=0>, 2.0 <ε=0>)

julia> typeof(ans)
Tuple{PrecisionCarrier{Float64}, PrecisionCarrier{Float64}, PrecisionCarrier{Float32}}

julia> precify(PrecisionCarrier{Float32}, [0, 1.0, 2.0f0])
3-element Vector{PrecisionCarrier{Float32}}:
 0.0 <ε=0>
 1.0 <ε=0>
 2.0 <ε=0>
source
PrecisionCarriers.epsilonsFunction
epsilons(p::PrecisionCarrier{T})

Return the number of epsilons of relative difference between p.big and p.x as an EpsT (Int64) value.

Note

Returns EpsMax (typemax(Int64)) if the difference is infinite, for example when the float reports Inf and the BigT has a non-infinite value.

source
PrecisionCarriers.significant_digitsFunction
significant_digits(p::PrecisionCarrier{T})

Return the number of significant decimal digits currently carried by this PrecisionCarrier.

julia> using PrecisionCarriers

julia> function unstable(x, N)
           y = abs(x)
           for i in 1:N y = sqrt(y) end
           w = y
           for i in 1:N w = w^2 end
           return w
       end
unstable (generic function with 1 method)

julia> unstable(precify(0.5), 30)
0.4999999971854335 <ε=25351362>

julia> significant_digits(ans)
8.249558483913594
source
PrecisionCarriers.reset_eps!Function
reset_eps!(p::PrecisionCarrier{AbstractFloat})

Reset the precision carrier to zero epsilons. Can be called on containers (AbstractArrays or Tuples) to reset all underlying PrecisionCarriers.

julia> using PrecisionCarriers

julia> function unstable(x, N)
           y = abs(x)
           for i in 1:N y = sqrt(y) end
           w = y
           for i in 1:N w = w^2 end
           return w
       end
unstable (generic function with 1 method)

julia> p = unstable(precify(1.5), 30)
1.4999996689838975 <ε=993842883>

julia> reset_eps!(p)
1.4999996689838975 <ε=0>

Custom types can be overloaded by implementing a function dispatching the call downwards to all relevant members. Note that this is a muting operation and therefore requires mutability of the members.

function reset_eps!(x::Custom)
    reset_eps!(x.v1)
    reset_eps!(x.v2)
    # ...
    return x
end
source
Base.eltypeFunction
Base.eltype(::PrecisionCarrier)

Return the internally carried floating point type.

source