@@ -6,53 +6,69 @@ Return the numerical precision of number/object `x`. If `x` is a floating-point
66floating-point type is returned; if `x` stores floating-point values, their promoted
77floating-point type is returned; otherwise, `AbstractFloat` is returned.
88
9- For type-stability, the precision shall be a *trait* which does only depend of the type of
10- `x`.
11-
12- Basically, `get_precision` supports numbers, and arrays or tuples of numbers. It can be
13- specialized for other object types defined in foreign packages. For objects of type, say
9+ By default, `get_precision` is applicable to any object or type and assuming that the
10+ precision is a *trait*, hence, which only depends on the type of `x`. This ensures
11+ *type-stability*. However, if a specific behavior must be implemented to a type, say,
1412`SomeType`, it is only needed to extend the method:
1513
1614```julia
1715TypeUtils.get_precision(::Type{T}) where {T<:SomeType} = ...
1816```
1917
20- See also [`adapt_precision`](@ref) and [`TypeUtils.Precision`](@ref).
21-
22- """
23- get_precision () = AbstractFloat
24- get_precision (x:: T ) where {T} = get_precision (T)
25- get_precision (:: Type ) = AbstractFloat # pass-through
26- get_precision (:: Type{T} ) where {T<: Precision } = T
27- get_precision (:: Type{<:Complex{T}} ) where {T} = get_precision (T)
28- get_precision (:: Type{<:AbstractArray{T}} ) where {T} = get_precision (T)
29- get_precision (:: Type{<:Factorization{T}} ) where {T} = get_precision (T)
18+ which shall return one of the floating-point types of union `TypeUtils.Precision` or
19+ `AbstractFloat`.
3020
31- # Second type parameter of a named tuple is a tuple of types.
32- get_precision ( :: Type{NamedTuple{S,T}} ) where {S,T} = get_precision (T)
21+ If 0, 2 or more arguments are specified, `get_precision` returns the promoted precision of
22+ all given arguments.
3323
34- # Deal with types of n-tuple for moderate values of n. These have the form `Type{A,B,C,...}`.
35- @inline get_precision (:: Type{T} ) where {T<: Tuple } = get_precision (unpack (T)... )
36-
37- # See https://discourse.julialang.org/t/inferable-unpacking-of-tuple-type-to-tuple-of-types/66329
38- @generated unpack (:: Type{T} ) where {T<: Tuple } = Tuple (T. parameters)
24+ See also [`adapt_precision`](@ref) and [`TypeUtils.Precision`](@ref).
3925
4026"""
41- get_precision(x, y, z...) -> T<:AbstractFloat
27+ get_precision (x:: Any ) = get_precision (typeof (x)) # precision is a trait
28+ get_precision (:: Type{T} ) where {T<: Precision } = T
29+ get_precision (:: Type{T} ) where {T<: Real } = AbstractFloat
30+ get_precision (:: Type{T} ) where {T<: TypeVar } = AbstractFloat
4231
43- Return the promoted precision of all given arguments `x`, `y`, and `z...`.
32+ # The following specialization is needed for abstract arrays like `StepRangeLen` which have
33+ # fields of higher precision to avoid rounding errors.
34+ get_precision (:: Type{<:AbstractArray{T}} ) where {T} = get_precision (T)
4435
45- """
36+ # Get precision for 0 or more than 2 arguments.
37+ get_precision () = AbstractFloat
4638@inline get_precision (x, y, z... ) = get_precision (get_precision (x, y), z... )
47- get_precision (x, y) =
48- get_precision (get_precision (x):: Type{<:AbstractFloat} ,
49- get_precision (y):: Type{<:AbstractFloat} ):: Type{<:AbstractFloat}
5039
40+ # Get precision of exactly 2 types. Type assertion in the most generic method is to avoid
41+ # stack-overflow for an invalid specialization.
5142get_precision (:: Type{AbstractFloat} , :: Type{AbstractFloat} ) = AbstractFloat
52- get_precision (:: Type{T} , :: Type{AbstractFloat} ) where {T<: AbstractFloat } = T
53- get_precision (:: Type{AbstractFloat} , :: Type{T} ) where {T<: AbstractFloat } = T
43+ get_precision (:: Type{T} , :: Type{AbstractFloat} ) where {T<: AbstractFloat } = get_precision (T)
44+ get_precision (:: Type{AbstractFloat} , :: Type{T} ) where {T<: AbstractFloat } = get_precision (T)
5445get_precision (:: Type{S} , :: Type{T} ) where {S<: AbstractFloat ,T<: AbstractFloat } =
55- promote_type (S, T):: Type{<:AbstractFloat}
46+ get_precision (promote_type (S, T))
47+ get_precision (x, y) = get_precision (get_precision (x):: Type{<:AbstractFloat} ,
48+ get_precision (y):: Type{<:AbstractFloat} )
49+
50+ # Return a simple vector of type parameters. (Must be defined before any generated function
51+ # that may use it.)
52+ function type_parameters (:: Type{T} ) where {T}
53+ try
54+ getfield (T, :parameters )
55+ catch
56+ try
57+ getfield (getfield (T, :body ), :parameters )
58+ catch
59+ Base. Core. svec ()
60+ end
61+ end
62+ end
63+
64+ # Default method for structure, tuple, and named tuple types.
65+ @generated function get_precision (:: Type{S} ) where {S}
66+ T = AbstractFloat
67+ for p in type_parameters (S)
68+ T = get_precision (T, p)
69+ end
70+ return T
71+ end
5672
5773"""
5874 adapt_precision(T::Type{<:AbstractFloat}, x) -> y
0 commit comments