Skip to content

Commit 5dcaf97

Browse files
authored
Add checked_mul for type suffix (#210)
This prevents MethodError due to lexical replacement of implicit `*` by macros. The constructors still check the input range by default.
1 parent 6b08f48 commit 5dcaf97

File tree

3 files changed

+40
-9
lines changed

3 files changed

+40
-9
lines changed

src/FixedPointNumbers.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox,
1212
import Statistics # for _mean_promote
1313
import Random: Random, AbstractRNG, SamplerType, rand!
1414

15-
import Base.Checked: checked_neg, checked_add, checked_sub, checked_div
15+
import Base.Checked: checked_neg, checked_add, checked_sub, checked_mul, checked_div
1616

1717
using Base: @pure
1818

@@ -36,8 +36,8 @@ export
3636
# Q and N typealiases are exported in separate source files
3737
# Functions
3838
scaledual,
39-
wrapping_neg, wrapping_add, wrapping_sub,
40-
saturating_neg, saturating_add, saturating_sub
39+
wrapping_neg, wrapping_add, wrapping_sub, wrapping_mul,
40+
saturating_neg, saturating_add, saturating_sub, saturating_mul
4141

4242
include("utilities.jl")
4343

@@ -56,6 +56,9 @@ nbitsint(::Type{X}) where {X <: FixedPoint} = bitwidth(X) - nbitsfrac(X) - signb
5656

5757
# construction using the (approximate) intended value, i.e., N0f8
5858
*(x::Real, ::Type{X}) where {X <: FixedPoint} = _convert(X, x)
59+
wrapping_mul(x::Real, ::Type{X}) where {X <: FixedPoint} = x % X
60+
saturating_mul(x::Real, ::Type{X}) where {X <: FixedPoint} = clamp(x, X)
61+
checked_mul(x::Real, ::Type{X}) where {X <: FixedPoint} = _convert(X, x)
5962

6063
# constructor-style conversions
6164
(::Type{X})(x::X) where {X <: FixedPoint} = x

test/fixed.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,23 @@ end
6464
@test_throws DomainError zero(Fixed{Int16,17})
6565
end
6666

67+
@testset "construction using type suffix" begin
68+
@test 0.635Q0f7 === Q0f7(0.635)
69+
@test 0.635Q5f10 === Q5f10(0.635)
70+
@test 0.635Q3f12 === Q3f12(0.635)
71+
@test 0.635Q1f14 === Q1f14(0.635)
72+
@test 0.635Q0f15 === Q0f15(0.635)
73+
74+
@test_throws ArgumentError 1.1Q0f7
75+
76+
@test wrapping_mul(0.635, Q0f7) === Q0f7(0.635)
77+
@test wrapping_mul(1.635, Q0f7) === Q0f7(-0.365)
78+
@test saturating_mul(0.635, Q0f7) === Q0f7(0.635)
79+
@test saturating_mul(1.635, Q0f7) === Q0f7(0.992)
80+
@test checked_mul(0.635, Q0f7) === Q0f7(0.635)
81+
@test_throws ArgumentError checked_mul(1.635, Q0f7)
82+
end
83+
6784
@testset "reinterpret/bitstring" begin
6885
@test reinterpret(Q0f7, signed(0xa2)) === -0.734375Q0f7
6986
@test reinterpret(Q5f10, signed(0x00a2)) === 0.158203125Q5f10

test/normed.jl

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,23 @@ end
1212
@test_throws DomainError zero(Normed{UInt16,17})
1313
end
1414

15+
@testset "construction using type suffix" begin
16+
@test 0.635N0f8 === N0f8(0.635)
17+
@test 0.635N6f10 === N6f10(0.635)
18+
@test 0.635N4f12 === N4f12(0.635)
19+
@test 0.635N2f14 === N2f14(0.635)
20+
@test 0.635N0f16 === N0f16(0.635)
21+
22+
@test_throws ArgumentError 1.1N0f8
23+
24+
@test wrapping_mul(0.635, N0f8) === N0f8(0.635)
25+
@test wrapping_mul(1.635, N0f8) === N0f8((1.635 * 255 - 256) / 255)
26+
@test saturating_mul(0.635, N0f8) === N0f8(0.635)
27+
@test saturating_mul(1.635, N0f8) === N0f8(1.0)
28+
@test checked_mul(0.635, N0f8) === N0f8(0.635)
29+
@test_throws ArgumentError checked_mul(1.635, N0f8)
30+
end
31+
1532
@testset "reinterpret/bitstring" begin
1633
@test reinterpret(N0f8, 0xa2).i === 0xa2
1734
@test reinterpret(N6f10, 0x1fa2).i === 0x1fa2
@@ -30,12 +47,6 @@ end
3047
@test bitstring(reinterpret(N0f8, 0xa2)) === "10100010"
3148
@test bitstring(reinterpret(N6f10, 0x00a2)) === "0000000010100010"
3249

33-
@test 0.635N0f8 == N0f8(0.635)
34-
@test 0.635N6f10 == N6f10(0.635)
35-
@test 0.635N4f12 == N4f12(0.635)
36-
@test 0.635N2f14 == N2f14(0.635)
37-
@test 0.635N0f16 == N0f16(0.635)
38-
3950
@test N0f8(1.0) == reinterpret(N0f8, 0xff)
4051
@test N0f8(0.5) == reinterpret(N0f8, 0x80)
4152
@test N2f14(1.0) == reinterpret(N2f14, 0x3fff)

0 commit comments

Comments
 (0)