Skip to content

Commit 2ecad9a

Browse files
authored
Merge pull request #5 from SymbolicML/protect-overflow
Error on overflow in dimensions variable
2 parents 0c2938f + 8fe7dc7 commit 2ecad9a

File tree

5 files changed

+39
-15
lines changed

5 files changed

+39
-15
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ version = "0.1.0"
66
[deps]
77
Ratios = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
88
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
9+
SaferIntegers = "88634af6-177f-5301-88b8-7819386cfa38"
910

1011
[weakdeps]
1112
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
@@ -16,6 +17,7 @@ DynamicQuantitiesUnitfulExt = "Unitful"
1617
[compat]
1718
Ratios = "0.4"
1819
Requires = "1"
20+
SaferIntegers = "3"
1921
Unitful = "1"
2022
julia = "1.6"
2123

src/math.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ Base.:+(l::Quantity, r::Quantity) = Quantity(l.value + r.value, l.dimensions, l.
2020
Base.:-(l::Quantity, r::Quantity) = Quantity(l.value - r.value, l.dimensions, l.valid && r.valid && l.dimensions == r.dimensions)
2121

2222
Base.:^(l::Quantity, r::Quantity) =
23-
let rr = tryrationalize(Int, r.value)
23+
let rr = tryrationalize(R, r.value)
2424
Quantity(l.value^rr, l.dimensions^rr, l.valid && r.valid && iszero(r.dimensions))
2525
end
2626
Base.:^(l::Dimensions, r::R) = @map_dimensions(Base.Fix1(*, r), l)
27-
Base.:^(l::Dimensions, r::Number) = l^tryrationalize(Int, r)
27+
Base.:^(l::Dimensions, r::Number) = l^tryrationalize(R, r)
2828
Base.:^(l::Quantity, r::Number) =
29-
let rr = tryrationalize(Int, r)
29+
let rr = tryrationalize(R, r)
3030
Quantity(l.value^rr, l.dimensions^rr, l.valid)
3131
end
3232

src/types.jl

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import Ratios: SimpleRatio
2+
import SaferIntegers: SafeInt
23

3-
const R = SimpleRatio{Int}
4+
const INT_TYPE = SafeInt
5+
const R = SimpleRatio{INT_TYPE}
6+
const ZERO = R(0)
47
const DIMENSION_NAMES = (:length, :mass, :time, :current, :temperature, :luminosity, :amount)
58
const DIMENSION_SYNONYMS = (:𝐋, :𝐌, :𝐓, :𝐈, :𝚯, :𝐉, :𝐍)
69
const SYNONYM_MAPPING = NamedTuple(DIMENSION_NAMES .=> DIMENSION_SYNONYMS)
@@ -34,13 +37,13 @@ struct Dimensions
3437
Dimensions(length::R, mass::R, time::R, current::R, temperature::R, luminosity::R, amount::R) =
3538
new(length, mass, time, current, temperature, luminosity, amount)
3639
Dimensions(; kws...) = Dimensions(
37-
tryrationalize(Int, get(kws, :length, 0 // 1)),
38-
tryrationalize(Int, get(kws, :mass, 0 // 1)),
39-
tryrationalize(Int, get(kws, :time, 0 // 1)),
40-
tryrationalize(Int, get(kws, :current, 0 // 1)),
41-
tryrationalize(Int, get(kws, :temperature, 0 // 1)),
42-
tryrationalize(Int, get(kws, :luminosity, 0 // 1)),
43-
tryrationalize(Int, get(kws, :amount, 0 // 1)),
40+
tryrationalize(R, get(kws, :length, ZERO)),
41+
tryrationalize(R, get(kws, :mass, ZERO)),
42+
tryrationalize(R, get(kws, :time, ZERO)),
43+
tryrationalize(R, get(kws, :current, ZERO)),
44+
tryrationalize(R, get(kws, :temperature, ZERO)),
45+
tryrationalize(R, get(kws, :luminosity, ZERO)),
46+
tryrationalize(R, get(kws, :amount, ZERO)),
4447
)
4548
end
4649

src/utils.jl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,14 @@ to_superscript(s::AbstractString) = join(
7979
end
8080
)
8181

82-
tryrationalize(::Type{<:Integer}, x::Rational) = R(x)
83-
tryrationalize(::Type{<:Integer}, x::Integer) = R(x)
84-
tryrationalize(::Type{<:Integer}, x) = simple_ratio_rationalize(x)
85-
simple_ratio_rationalize(x) = isinteger(x) ? R(round(Int, x)) : R(rationalize(Int, x))
82+
tryrationalize(::Type{RI}, x::RI) where {RI} = x
83+
tryrationalize(::Type{RI}, x::Rational) where {RI} = RI(x)
84+
tryrationalize(::Type{RI}, x::Integer) where {RI} = RI(x)
85+
tryrationalize(::Type{RI}, x) where {RI} = simple_ratio_rationalize(RI, x)
86+
simple_ratio_rationalize(::Type{RI}, x) where {RI} =
87+
let int_type = RI.parameters[1]
88+
isinteger(x) ? RI(round(int_type, x)) : RI(rationalize(int_type, x))
89+
end
8690

8791
"""
8892
ustrip(q::Quantity)

test/unittests.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using DynamicQuantities
2+
using DynamicQuantities: INT_TYPE, R
23
using Test
34

45
@testset "Basic utilities" begin
@@ -149,4 +150,18 @@ end
149150
d = Dimensions(length=-0.2, luminosity=2)
150151
q = Quantity(0.5, inv(d))
151152
@test q == Quantity(0.5, length=0.2, luminosity=-2)
153+
end
154+
155+
@testset "Trigger overflow" begin
156+
f(x, N) =
157+
let
158+
for _ = 1:N
159+
x = x + R(2 // 3)
160+
x = x - R(2 // 3)
161+
end
162+
x
163+
end
164+
165+
@test f(R(5 // 7), 15) == R(5 // 7)
166+
@test_throws OverflowError f(R(5 // 7), 20)
152167
end

0 commit comments

Comments
 (0)