Repository navigation
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #362 +/- ##
==========================================
- Coverage 96.75% 96.74% -0.01%
==========================================
Files 7 7
Lines 800 799 -1
==========================================
- Hits 774 773 -1
Misses 26 26 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
PatrickHaecker
left a comment
There was a problem hiding this comment.
I think this would currently violate the promised interface, but the fix seems plausible. LGTM with the fix.
I still haven't understood why this is better than just doing a 0.10 release in the next days, but that is irrelevant in terms of correctness.
| floattype(::Type{X}) where {T <: ShortInts, X <: FixedPoint{T}} = Float32 | ||
| floattype(::Type{X}) where {T <: Integer, X <: FixedPoint{T}} = Float64 | ||
| floattype(::Type{X}) where {T <: LongInts, X <: FixedPoint{T}} = BigFloat | ||
| floattype(::Type{<:FixedPoint}) = BigFloat # fallback for `FixedPoint` |
There was a problem hiding this comment.
Your proposal would return BigFloat for Union{N0f8, N0f16}, which in my read violates the docstring: "In general the returned type should have the minimum bitwidth needed to encode the full precision of the input type."
Not perfect, but I think better:
| floattype(::Type{<:FixedPoint}) = BigFloat # fallback for `FixedPoint` | |
| floattype(::Type{T}) where {T <: FixedPoint} = | |
| T isa Union ? promote_type(map(floattype, Base.uniontypes(T))...) : BigFloat |
There was a problem hiding this comment.
As far as non-concrete types are concerned, I don't think that document makes much sense.
BTW, have you read this comment? #343 (comment)
As you've probably noticed, we can create various edge cases (e.g., Union{N0f8, Float32}).
| @test floattype(FixedPoint) === BigFloat | ||
| @test floattype(Normed) === BigFloat | ||
| @test floattype(Fixed) === BigFloat | ||
| @test floattype(FixedPoint{Int8}) === Float32 | ||
| @test floattype(Normed{UInt32}) === Float64 | ||
| @test floattype(Fixed{Int64}) === BigFloat | ||
| @test floattype(FixedPoint{MyInteger}) === Float64 | ||
| @test floattype(FixedPoint{Union{},1}) === BigFloat | ||
| @test floattype(Normed{Unsigned,2}) === BigFloat | ||
| @test floattype(Fixed{T,3} where {T<:Signed}) === BigFloat |
There was a problem hiding this comment.
Please add few non-trivial Union cases, too.
| """ | ||
| floattype(::Type{T})::Type{<:AbstractFloat} | ||
|
|
||
| Return a minimal type suitable for performing computations with instances of type `T` without integer overflow. | ||
|
|
||
| The fallback definition of `floattype(T)` applies only to `T<:AbstractFloat`. | ||
| However, it is permissible to extend `floattype` to return types that are not subtypes of | ||
| `AbstractFloat`; the key characteristic is that the return type should support computation without integer overflow. | ||
|
|
||
| In general the returned type should have the minimum bitwidth needed to encode the full precision of the input type. | ||
| however, a priority should be placed on computational efficiency; consequently, types like `Float16` should be avoided | ||
| except in scenarios where they are guaranteed to have hardware support. | ||
|
|
||
| # Examples | ||
|
|
||
| A classic usage is to avoid overflow behavior by promoting `FixedPoint` to `AbstractFloat` | ||
|
|
||
| ```jldoctest; setup = :(using FixedPointNumbers) | ||
| julia> x = N0f8(1.0) | ||
| 1.0N0f8 | ||
|
|
||
| julia> x + x # overflow | ||
| 0.996N0f8 | ||
|
|
||
| julia> T = floattype(x) | ||
| Float32 | ||
|
|
||
| julia> T(x) + T(x) | ||
| 2.0f0 | ||
| ``` | ||
|
|
||
| The following represents a valid extension of `floattype` to non-AbstractFloats: | ||
|
|
||
| ```julia | ||
| julia> using FixedPointNumbers, ColorTypes | ||
|
|
||
| julia> floattype(RGB{N0f8}) | ||
| RGB{Float32} | ||
| ``` | ||
|
|
||
| `RGB` itself is not a subtype of `AbstractFloat`, but unlike `RGB{N0f8}` operations with `RGB{Float32}` are not subject to integer overflow. | ||
| """ |
There was a problem hiding this comment.
The docstring had some weaknesses and should describe the new situation explicitly:
| """ | |
| floattype(::Type{T}) | |
| floattype(x::FixedPoint) | |
| Return a minimal type suitable for performing computations with instances of type `T` without integer overflow. | |
| For a `Real` type `T`, the returned type is a subtype of `AbstractFloat`. In general it has the minimum bitwidth | |
| needed to encode the full precision of `T`. However, computational efficiency takes priority, so the returned type | |
| may be wider. For example, `floattype(N0f8)` is currently `Float32` rather than `Float16`. | |
| For a non-concrete `FixedPoint` type, the returned type suits all of its concrete subtypes. A `Union` of `FixedPoint` | |
| types gives the promoted type of its members. Any other non-concrete `FixedPoint` type gives `floattype(R)` if its raw | |
| type `R` is concrete, and `BigFloat` otherwise. | |
| Methods are defined for `AbstractFloat`, `Integer`, `Rational`, `AbstractIrrational` and `FixedPoint` types. Other | |
| `Real` types currently return `T` itself with a deprecation warning, and will throw a `MethodError` in a future | |
| release. Packages may extend `floattype` to types that are not `Real`, as long as the returned type supports | |
| computation without integer overflow. | |
| # Examples | |
| A classic usage is to avoid overflow by converting `FixedPoint` values to a floating-point type: | |
| ```jldoctest; setup = :(using FixedPointNumbers) | |
| julia> x = N0f8(1.0) | |
| 1.0N0f8 | |
| julia> x + x # overflow | |
| 0.996N0f8 | |
| julia> T = floattype(x) | |
| Float32 | |
| julia> T(x) + T(x) | |
| 2.0f0 |
Non-concrete FixedPoint types:
julia> floattype(Normed{UInt8})
Float32
julia> floattype(Union{N0f8, N0f16})
Float32
julia> floattype(Normed)
BigFloat
The following represents a valid extension of floattype to types that are not subtypes of AbstractFloat:
julia> using FixedPointNumbers, ColorTypes
julia> floattype(RGB{N0f8})
RGB{Float32}RGB itself is not a subtype of AbstractFloat, but unlike RGB{N0f8}, operations with RGB{Float32} are not subject
to integer overflow.
"""
There was a problem hiding this comment.
Aside from the fact that it's long, I think the proposal isn't bad.
However, I don't understand exactly what purpose it serves.
This document is primarily intended for package developers. I don't know of any examples where floattype is actually being used outside of ColorTypes and its downstream packages.
I think the top-down definition of floattype should be discussed in JuliaLang/julia rather than in this package.
|
@PatrickHaecker |
|
@kimikage
The
julia> promote_type(Int128, Float16)
Float16That seems a bit extreme to me, but that is what we should go for if we want to be as compatible as possible to
julia> promote_type(Union{Int8, Int16}, Float32)
RealSo we probably don't want to strive for maximum w = vcat(Int8[100], Int32[3])
w[1] + w[1] # 200: the Int8 was converted to Int32
w = vcat(Int16[100], Int32[3])
w[1] + w[1] # 200: the Int16 was converted to Int32
a = Union{Int8, Int16}[Int8(100)]
v = vcat(a, Int32[3]) # eltype Signed, elements Int8, Int16, Int32
v[1] + v[1] # -56: Int8 arithmetic overflowsI reported that. Should we maybe see whether that report provides any insights? |
|
First of all, since this package is still at v0.x, I don’t think it’s necessary to mark something as deprecated before introducing breaking changes. I thought you were eager to switch from v0.9.x to v0.10, so I'm not quite sure what your priorities are anymore. My intention is, at the very least, to ensure that IMO, the situation that In light of PR #341, what should be my next step? |
This is a variant of PR #354 with deprecated fallback method retained.
While it would be hypocritical not to call this a breaking change, it does allow us to avoid a direct violation of SemVer.
In other words, I plan to release this in the v0.9 series.