Skip to content

Commit 8a4df8c

Browse files
committed
Fix promotion scheme by not promoting value type itself
1 parent 31259ee commit 8a4df8c

File tree

3 files changed

+30
-11
lines changed

3 files changed

+30
-11
lines changed

src/math.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
for (type, base_type, _) in ABSTRACT_QUANTITY_TYPES
22
@eval begin
33
function Base.:*(l::$type, r::$type)
4-
l, r = promote(l, r)
4+
l, r = promote_except_value(l, r)
55
new_quantity(typeof(l), ustrip(l) * ustrip(r), dimension(l) * dimension(r))
66
end
77
function Base.:/(l::$type, r::$type)
8-
l, r = promote(l, r)
8+
l, r = promote_except_value(l, r)
99
new_quantity(typeof(l), ustrip(l) / ustrip(r), dimension(l) / dimension(r))
1010
end
1111
function Base.div(x::$type, y::$type, r::RoundingMode=RoundToZero)
12-
x, y = promote(x, y)
12+
x, y = promote_except_value(x, y)
1313
new_quantity(typeof(x), div(ustrip(x), ustrip(y), r), dimension(x) / dimension(y))
1414
end
1515

@@ -57,7 +57,7 @@ Base.:/(l::AbstractDimensions, r::AbstractDimensions) = map_dimensions(-, l, r)
5757
for (type, base_type, _) in ABSTRACT_QUANTITY_TYPES, op in (:+, :-)
5858
@eval begin
5959
function Base.$op(l::$type, r::$type)
60-
l, r = promote(l, r)
60+
l, r = promote_except_value(l, r)
6161
dimension(l) == dimension(r) || throw(DimensionError(l, r))
6262
return new_quantity(typeof(l), $op(ustrip(l), ustrip(r)), dimension(l))
6363
end
@@ -81,7 +81,7 @@ for op in (:*, :/, :+, :-, :div, :atan, :atand, :copysign, :flipsign, :mod),
8181

8282
t1 == t2 && continue
8383

84-
@eval Base.$op(l::$t1, r::$t2) = $op(promote(l, r)...)
84+
@eval Base.$op(l::$t1, r::$t2) = $op(promote_except_value(l, r)...)
8585
end
8686

8787
# We don't promote on the dimension types:
@@ -156,7 +156,7 @@ for (type, base_type, _) in ABSTRACT_QUANTITY_TYPES, f in (:atan, :atand)
156156
return $f(ustrip(x))
157157
end
158158
function Base.$f(y::$type, x::$type)
159-
y, x = promote(y, x)
159+
y, x = promote_except_value(y, x)
160160
dimension(y) == dimension(x) || throw(DimensionError(y, x))
161161
return $f(ustrip(y), ustrip(x))
162162
end
@@ -186,7 +186,7 @@ for (type, base_type, _) in ABSTRACT_QUANTITY_TYPES, f in (:copysign, :flipsign,
186186
# and ignore any dimensions on y, since those will cancel out.
187187
@eval begin
188188
function Base.$f(x::$type, y::$type)
189-
x, y = promote(x, y)
189+
x, y = promote_except_value(x, y)
190190
return new_quantity(typeof(x), $f(ustrip(x), ustrip(y)), dimension(x))
191191
end
192192
function Base.$f(x::$type, y::$base_type)

src/utils.jl

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,25 @@ function Base.promote_rule(::Type{<:AbstractQuantity}, ::Type{<:Number})
4646
return Number
4747
end
4848

49+
"""
50+
promote_except_value(q1::UnionAbstractQuantity, q2::UnionAbstractQuantity)
51+
52+
This applies a promotion to the quantity type, and the dimension type,
53+
but *not* the value type. This is necessary because sometimes we would
54+
want to multiply a quantity array with a scalar quantity, and wish to use
55+
promotion on the quantity type itself, but don't want to promote to a
56+
single value type.
57+
"""
58+
@inline function promote_except_value(q1::Q1, q2::Q2) where {T1,D1,T2,D2,Q1<:UnionAbstractQuantity{T1,D1},Q2<:UnionAbstractQuantity{T2,D2}}
59+
Q = promote_type(Q1, Q2)
60+
D = promote_type(D1, D2)
61+
62+
Q1_out = with_type_parameters(Q, T1, D)
63+
Q2_out = with_type_parameters(Q, T2, D)
64+
return convert(Q1_out, q1), convert(Q2_out, q2)
65+
end
66+
@inline promote_except_value(q1::Q, q2::Q) where {Q<:UnionAbstractQuantity} = (q1, q2)
67+
4968
Base.keys(d::AbstractDimensions) = dimension_names(typeof(d))
5069
Base.getindex(d::AbstractDimensions, k::Symbol) = getfield(d, k)
5170

@@ -77,7 +96,7 @@ Base.keys(q::UnionAbstractQuantity) = keys(ustrip(q))
7796

7897
# Numeric checks
7998
function Base.isapprox(l::UnionAbstractQuantity, r::UnionAbstractQuantity; kws...)
80-
l, r = promote(l, r)
99+
l, r = promote_except_value(l, r)
81100
return isapprox(ustrip(l), ustrip(r); kws...) && dimension(l) == dimension(r)
82101
end
83102
function Base.isapprox(l::Number, r::UnionAbstractQuantity; kws...)
@@ -90,14 +109,14 @@ function Base.isapprox(l::UnionAbstractQuantity, r::Number; kws...)
90109
end
91110
Base.iszero(d::AbstractDimensions) = all_dimensions(iszero, d)
92111
function Base.:(==)(l::UnionAbstractQuantity, r::UnionAbstractQuantity)
93-
l, r = promote(l, r)
112+
l, r = promote_except_value(l, r)
94113
ustrip(l) == ustrip(r) && dimension(l) == dimension(r)
95114
end
96115
Base.:(==)(l::Number, r::UnionAbstractQuantity) = ustrip(l) == ustrip(r) && iszero(dimension(r))
97116
Base.:(==)(l::UnionAbstractQuantity, r::Number) = ustrip(l) == ustrip(r) && iszero(dimension(l))
98117
Base.:(==)(l::AbstractDimensions, r::AbstractDimensions) = all_dimensions(==, l, r)
99118
function Base.isless(l::UnionAbstractQuantity, r::UnionAbstractQuantity)
100-
l, r = promote(l, r)
119+
l, r = promote_except_value(l, r)
101120
dimension(l) == dimension(r) || throw(DimensionError(l, r))
102121
return isless(ustrip(l), ustrip(r))
103122
end

test/unittests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ end
676676
q = convert(Q{Float16}, 1.5u"g")
677677
qs = uconvert(convert(Q{Float16}, us"g"), 5 * q)
678678
@test typeof(qs) <: Q{Float16,<:SymbolicDimensions{<:Any}}
679-
@test qs 7.5us"g"
679+
@test isapprox(qs, 7.5us"g"; atol=0.01)
680680

681681
# Arrays
682682
x = [1.0, 2.0, 3.0] .* Q(u"kg")

0 commit comments

Comments
 (0)