Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve the floating-point precision of quantities in uconvert #754

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/conversion.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
"""
UnitConversionFactor(x::T) where {T<:AbstractFloat}
Conversion factor with value `x`.

Used by the [`convfact`](@ref) function to preserve
the floating-point precision of quantities.
"""
struct UnitConversionFactor{T<:AbstractFloat} <: AbstractIrrational
x::T
# the inner constructor necessary for ambiguity resolution
UnitConversionFactor(x::T) where {T<:AbstractFloat} = new{T}(x)
eliascarv marked this conversation as resolved.
Show resolved Hide resolved
end

Base.:(==)(a::UnitConversionFactor, b::UnitConversionFactor) = a.x == b.x
Base.hash(x::UnitConversionFactor, h::UInt) = hash(x.x, h)
Base.BigFloat(x::UnitConversionFactor) = BigFloat(x.x)
Base.Float64(x::UnitConversionFactor) = Float64(x.x)
Base.Float32(x::UnitConversionFactor) = Float32(x.x)

"""
convfact(s::Units, t::Units)
Find the conversion factor from unit `t` to unit `s`, e.g., `convfact(m, cm) == 1//100`.
Expand Down Expand Up @@ -37,7 +56,7 @@ Find the conversion factor from unit `t` to unit `s`, e.g., `convfact(m, cm) ==
"exponents and/or SI prefixes in units"
))
end
return :($result)
return result isa AbstractFloat ? UnitConversionFactor(result) : result
end

"""
Expand Down
18 changes: 18 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,24 @@ end
# Issue 647:
@test uconvert(u"kb^1000", 1u"kb^1001 * b^-1") === 1000u"kb^1000"
@test uconvert(u"kOe^1000", 1u"kOe^1001 * Oe^-1") === 1000u"kOe^1000"
# Issue 753:
# preserve the floating-point precision of quantities
@test Unitful.numtype(uconvert(m, BigFloat(100)cm)) === BigFloat
@test Unitful.numtype(uconvert(cm, (BigFloat(1)π + im) * m)) === Complex{BigFloat}
@test Unitful.numtype(uconvert(rad, BigFloat(360)°)) === BigFloat
@test Unitful.numtype(uconvert(°, (BigFloat(2)π + im) * rad)) === Complex{BigFloat}
@test Unitful.numtype(uconvert(m, 100.0cm)) === Float64
@test Unitful.numtype(uconvert(cm, (1.0π + im) * m)) === ComplexF64
@test Unitful.numtype(uconvert(rad, 360.0°)) === Float64
@test Unitful.numtype(uconvert(°, (2.0π + im) * rad)) === ComplexF64
@test Unitful.numtype(uconvert(m, 100f0cm)) === Float32
eliascarv marked this conversation as resolved.
Show resolved Hide resolved
@test Unitful.numtype(uconvert(cm, (1f0π + im) * m)) === ComplexF32
@test Unitful.numtype(uconvert(rad, 360f0°)) === Float32
@test Unitful.numtype(uconvert(°, (2f0π + im) * rad)) === ComplexF32
@test Unitful.numtype(uconvert(m, Float16(100)cm)) === Float16
@test Unitful.numtype(uconvert(cm, (Float16(1)π + im) * m)) === ComplexF16
@test Unitful.numtype(uconvert(rad, Float16(360)°)) === Float16
@test Unitful.numtype(uconvert(°, (Float16(2)π + im) * rad)) === ComplexF16
# Floating point overflow/underflow in uconvert can happen if the
# conversion factor is large, because uconvert does not cancel
# common basefactors (or just for really large exponents and/or
Expand Down
Loading