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

Merged
merged 11 commits into from
Dec 20, 2024
15 changes: 14 additions & 1 deletion src/conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ Returns 1. (Avoids effort when unnecessary.)
"""
convfact(s::Units{S}, t::Units{S}) where {S} = 1

"""
convfact(T::Type, s::Units, t::Units)
Returns the appropriate conversion factor from unit `t` to unit `s` for the number type `T`.
"""
function convfact(::Type{T}, s::Units, t::Units) where {T<:Number}
cf = convfact(s, t)
if cf isa AbstractFloat
eliascarv marked this conversation as resolved.
Show resolved Hide resolved
convert(float(real(T)), cf)
else
cf
end
end

"""
uconvert(a::Units, x::Quantity{T,D,U}) where {T,D,U}
Convert a [`Unitful.Quantity`](@ref) to different units. The conversion will
Expand All @@ -69,7 +82,7 @@ function uconvert(a::Units, x::Quantity{T,D,U}) where {T,D,U}
elseif (a isa AffineUnits) || (x isa AffineQuantity)
return uconvert_affine(a, x)
else
return Quantity(x.val * convfact(a, U()), a)
return Quantity(x.val * convfact(T, a, U()), a)
end
end

Expand Down
6 changes: 6 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ 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:
# avoid converting the float type of quantities
@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
# 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