From b1531a64aefc1a05a8277d7352958682662e13d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4cker?= Date: Sat, 10 Oct 2026 03:58:09 +0200 Subject: [PATCH 1/3] Test code paths that no test reached Covers reductions over empty and one-element arrays, `checked_mul` for `f == 0`, the generic `AbstractFloat` conversion of `Normed`, hashing of values that equal a `Rational` (which goes through `decompose`), `%` of a foreign `Real` type, and the deprecated `floattype` fallback. The reductions, the hashing and `%` behave the same for `Fixed` and `Normed`, so common test functions check them over many raw types and fractional bits. --- test/common.jl | 31 +++++++++++++++++++++++++++++++ test/fixed.jl | 10 ++++++++++ test/normed.jl | 9 +++++++++ test/traits.jl | 2 ++ 4 files changed, 52 insertions(+) diff --git a/test/common.jl b/test/common.jl index def7f6b5..32b4eeb2 100644 --- a/test/common.jl +++ b/test/common.jl @@ -153,11 +153,32 @@ function test_convert_from_nan(TX::Type) end end +function test_hash_rational(TX::Type) + @testset "hash(::$X)" for X in target(TX, :i8, :i16, :i32, :i64; ex = :thin) + for x in (zero(X), eps(X), typemin(X), typemax(X)) + @test x == Rational(x) + @test hash(x) == hash(Rational(x)) + end + end +end + +# a `Real` type with only the methods that `x % X` needs +struct IntReal <: Real + i::Int +end +Base.:*(a::Integer, x::IntReal) = IntReal(a * x.i) +Base.:*(x::IntReal, a::AbstractFloat) = IntReal(Int(x.i * a)) +Base.isfinite(::IntReal) = true +Base.round(x::IntReal) = x +Base.unsafe_trunc(::Type{T}, x::IntReal) where {T <: Integer} = x.i % T + function test_rem_type(TX::Type) @testset "% $X" for X in target(TX, :i8, :i16; ex = :thin) xs = typemin(X):0.1:typemax(X) @test all(x -> x % X === X(x), xs) @test wrapping_rem(2, X) === saturating_rem(2, X) === checked_rem(2, X) === 2 % X + @test IntReal(1) % X === 1 % X + @test IntReal(2) % X === 2 % X end end @@ -400,6 +421,16 @@ function test_isinteger(TX::Type) end end +function test_reductions_short(TX::Type) + @testset "sum/prod(::Vector{$X})" for X in target(TX; ex = :thin) + x = typemax(X) + @test sum(X[]) === 0.0 + @test prod(X[]) === 1.0 + @test sum([x]) === Float64(x) + @test prod([x]) === Float64(x) + end +end + function test_rand(TX::Type) @testset "rand(::$X)" for X in target(TX; ex = :thin) @test isa(rand(X), X) diff --git a/test/fixed.jl b/test/fixed.jl index d0909c3b..55520d7a 100644 --- a/test/fixed.jl +++ b/test/fixed.jl @@ -229,6 +229,8 @@ end @test rationalize(Int16, 0.81Q3f4) === Rational{Int16}(13//16) @test rationalize(-0.81Q3f4, tol=0.02) === Rational{Int}(-13//16) @test rationalize(Int8, -0.81Q3f4, tol=0.07) === Rational{Int8}(-3//4) + + test_hash_rational(Fixed) end @testset "BigFloat conversions" begin @@ -403,6 +405,12 @@ end end test_mul(Fixed) + # `f == 0` has its own overflow bounds + @test checked_mul(Q7f0(127), Q7f0(1)) === Q7f0(127) + @test checked_mul(Q7f0(-64), Q7f0(2)) === Q7f0(-128) + @test_throws OverflowError checked_mul(Q7f0(64), Q7f0(2)) + @test_throws OverflowError checked_mul(Q7f0(-128), Q7f0(-1)) + FixedPointNumbers.mul_with_rounding(1.5Q6f1, 0.5Q6f1, RoundNearest) === 1.0Q6f1 FixedPointNumbers.mul_with_rounding(1.5Q6f1, -0.5Q6f1, RoundNearest) === -1.0Q6f1 FixedPointNumbers.mul_with_rounding(1.5Q6f1, 0.5Q6f1, RoundNearestTiesUp) === 1.0Q6f1 @@ -694,6 +702,8 @@ end acmp = Float64(a[1])*Float64(a[2]) @test prod(a) == acmp @test prod(a, dims=1) == [acmp] + + test_reductions_short(Fixed) end @testset "reductions, Statistics" begin diff --git a/test/normed.jl b/test/normed.jl index 50b60093..1221c2fe 100644 --- a/test/normed.jl +++ b/test/normed.jl @@ -193,6 +193,8 @@ end @test rationalize(Int16, 0.804N0f8) === Rational{Int16}(41//51) @test rationalize(0.804N0f8, tol=0.002) === Rational{Int}(41//51) @test rationalize(Int8, 0.804N0f8, tol=0.005) === Rational{Int8}(4//5) + + test_hash_rational(Normed) end @testset "BigFloat conversions" begin @@ -252,6 +254,11 @@ end @test isa(y, T) end + # the generic method serves `AbstractFloat` types without a dedicated method + for Tf in (Float16, Float32, Float64), x in (0.2N0f8, 0.2N0f16, 0.2N2f14, 0.2N0f32, 0.2N0f64) + @test invoke(Tf, Tuple{Normed}, x) === Tf(x) + end + for Tf in (Float16, Float32, Float64) @testset "$Tf(::$N)" for N in target(Normed, :i8, :i16) T = rawtype(N) @@ -672,6 +679,8 @@ end acmp = Float64(a[1])*Float64(a[2]) @test prod(a) == acmp @test prod(a, dims=1) == [acmp] + + test_reductions_short(Normed) end @testset "reductions, Statistics" begin diff --git a/test/traits.jl b/test/traits.jl index c248b4c0..a99621d3 100644 --- a/test/traits.jl +++ b/test/traits.jl @@ -17,4 +17,6 @@ struct MyReal <: Real end @test floattype(typeof(π)) === Float64 @test_skip(@test_throws MethodError floattype(MyReal)) # TODO: eliminate `@test_skipped` when depwarn is eliminated. See #177. + # meanwhile, the deprecated fallback warns and returns the type unchanged + @test (@test_logs (:warn, r"fallback definition of `floattype`") floattype(MyReal)) === MyReal end From aed366b4b04c6a26076894f0f88692d38b90cc09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4cker?= Date: Sat, 10 Oct 2026 06:08:23 +0200 Subject: [PATCH 2/3] Remove an unreachable return in `Float32(::Normed{UInt8})` `Normed{UInt8,f}` requires `1 <= f <= 8`, so after the checks for `f <= 7` only `f == 8` remains and the final `0.0f0` could never be returned. --- src/normed.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/normed.jl b/src/normed.jl index 21ad969a..7bc7e87d 100644 --- a/src/normed.jl +++ b/src/normed.jl @@ -157,8 +157,7 @@ function Base.Float32(x::Normed{UInt8,f}) where f f == 5 && return Float32(Int32(x.i) * 0x003) * @f32(0xb02c0bp-30) f == 6 && return Float32(Int32(x.i) * 0x049) * @f32(0xe40039p-36) f == 7 && return Float32(Int32(x.i) * 0x01f) * @f32(0x852b5fp-35) - f == 8 && return Float32(Int32(x.i) * 0x155) * @f32(0xc0f0fdp-40) - 0.0f0 + #= f == 8 =# return Float32(Int32(x.i) * 0x155) * @f32(0xc0f0fdp-40) end function Base.Float32(x::Normed{UInt16,f}) where f f32 = Float32(x.i) From 962d56198288bee232a0db9926e63449b4c2cd06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4cker?= Date: Sat, 10 Oct 2026 06:08:23 +0200 Subject: [PATCH 3/3] Require Julia 1.6 No CI job has tested a Julia version before 1.6 for a long time. Dropping them removes code that no tested version could run: the workarounds for `copysign`/`flipsign` with an unsigned sign argument (Julia 1.0 and 1.1), for `Base.showarg` of arrays (before 1.6) and for precompilation (1.0). Julia 1.6 also makes further workarounds unnecessary. `@exp2` and the `@generated` `inv_rawone` only forced constant folding, and plain `exp2` and division compile to identical code on Julia 1.6, 1.10 and 1.13. The `signed`/`unsigned` methods only kept Julia 1.0 from converting to an integer, and without them both still throw a `MethodError`. `Random = "1"` resolves on Julia 1.6, so the `<0.0.1` alternative is not needed. CI now tests Julia 1.6. The version becomes 0.10.0, because releases for older Julia versions end here. --- .github/workflows/UnitTest.yml | 3 +++ Project.toml | 6 +++--- src/FixedPointNumbers.jl | 37 ++++++---------------------------- src/fixed.jl | 32 ++++++++++++++--------------- src/normed.jl | 16 +++++++-------- src/utilities.jl | 4 ---- test/common.jl | 10 ++++----- test/fixed.jl | 18 ++++++----------- test/normed.jl | 17 +++++----------- 9 files changed, 51 insertions(+), 92 deletions(-) diff --git a/.github/workflows/UnitTest.yml b/.github/workflows/UnitTest.yml index fa28a12a..89843cf0 100644 --- a/.github/workflows/UnitTest.yml +++ b/.github/workflows/UnitTest.yml @@ -31,6 +31,9 @@ jobs: os: [ubuntu-latest, windows-latest, macos-15-intel] julia-arch: [x64] include: + - os: ubuntu-latest # the minimum supported version + julia-version: '1.6' + julia-arch: x64 - os: ubuntu-latest # only test one 32-bit job julia-version: '1' julia-arch: x86 diff --git a/Project.toml b/Project.toml index d7afc927..199cacd6 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "FixedPointNumbers" uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" -version = "0.9.2" +version = "0.10.0" [deps] Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" @@ -15,11 +15,11 @@ FixedPointNumbersStatisticsExt = "Statistics" [compat] Aqua = "0.8" Documenter = "0.27, 1" -Random = "<0.0.1, 1" +Random = "1" StableRNGs = "1" Statistics = "1" Test = "1" -julia = "1" +julia = "1.6" [extras] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" diff --git a/src/FixedPointNumbers.jl b/src/FixedPointNumbers.jl index 7bafaca2..5105918b 100644 --- a/src/FixedPointNumbers.jl +++ b/src/FixedPointNumbers.jl @@ -6,7 +6,7 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox, zero, oneunit, one, typemin, typemax, floatmin, floatmax, eps, reinterpret, big, rationalize, float, trunc, round, floor, ceil, bswap, clamp, div, fld, cld, rem, mod, mod1, fld1, min, max, minmax, - signed, unsigned, sign, copysign, flipsign, signbit, + sign, copysign, flipsign, signbit, length, widen, widemul import Random: Random, AbstractRNG, SamplerType, rand! @@ -137,8 +137,7 @@ zero(::Type{X}) where {X <: FixedPoint} = X(zero(rawtype(X)), 0) oneunit(::Type{X}) where {X <: FixedPoint} = X(rawone(X), 0) one(::Type{X}) where {X <: FixedPoint} = oneunit(X) -# for Julia v1.0, which does not fold `div_float` before inlining -inv_rawone(x) = (@generated) ? (y = 1.0 / rawone(x); :($y)) : 1.0 / rawone(x) +inv_rawone(x) = 1.0 / rawone(x) # traits eps(::Type{X}) where {X <: FixedPoint} = X(oneunit(rawtype(X)), 0) @@ -357,36 +356,24 @@ bitstring(x::FixedPoint) = bitstring(x.i) bswap(x::X) where {X <: FixedPoint} = sizeof(X) == 1 ? x : X(bswap(x.i), 0) -# At least on Julia v1.5.0 or earlier, the following specialization helps the -# SIMD vectorization. (cf. PR #194) +# Julia 1.10 and earlier vectorize the loops over `clamp` only with this specialization. (cf. PR #194) clamp(x::X, lo::X, hi::X) where {X <: FixedPoint} = X(clamp(x.i, lo.i, hi.i), 0) clamp(x, ::Type{X}) where {X <: FixedPoint} = clamp(x, typemin(X), typemax(X)) % X -# Since `FixedPoint` is not an integer type, it is not clear in what type -# `signed` and `unsigned` for `FixedPoint` should return values. They should -# currently throw errors in case we support "unsigned Fixed" or "signed Normed" -# in the future. The following "incomplete" code is necessary for Julia v1.0 -# etc. to prevent accidental conversion to an integer type. -signed(x::X) where {X <: FixedPoint} = signed(X)(signed(x.i), 0) -unsigned(x::X) where {X <: FixedPoint} = unsigned(X)(unsigned(x.i), 0) - function sign(x::X) where {T, X <: FixedPoint{T}} T <: Unsigned && return iszero(x) ? x : oneunit(X) # `Q0f7`, etc., result in an error for `oneunit(X)`. x <= zero(X) && return x === zero(X) ? x : X(-1) return oneunit(X) end + function copysign(x::X, y::Real) where {T, X <: FixedPoint{T}} T <: Signed ? X(copysign(x.i, y), 0) : throw_not_a_signed_number_error(x) end function flipsign(x::X, y::Real) where {T, X <: FixedPoint{T}} T <: Signed ? X(flipsign(x.i, y), 0) : throw_not_a_signed_number_error(x) end -if copysign(-1, 0x1) !== 1 # for Julia v1.0 and v1.1 (julia #30748) - copysign(x::X, y::Unsigned) where {T, X <: FixedPoint{T}} = copysign(x, signed(y)) - flipsign(x::X, y::Unsigned) where {T, X <: FixedPoint{T}} = flipsign(x, signed(y)) -end @noinline function throw_not_a_signed_number_error(x) throw(ArgumentError("$x is not a signed number.")) end @@ -515,16 +502,6 @@ function show(io::IO, x::FixedPoint{T,f}) where {T,f} return nothing end -if VERSION < v"1.6.0-DEV.356" # JuliaLang/julia#36107 - function Base.showarg(io::IO, a::Array{X}, toplevel) where {X<:FixedPoint} - toplevel || print(io, "::") - print(io, "Array{") - showtype(io, X) - print(io, ",$(ndims(a))}") - toplevel && hasalias(X) && print(io, " with eltype ", X) - end -end - include("fixed.jl") include("normed.jl") include("deprecations.jl") @@ -666,9 +643,7 @@ if !isdefined(Base, :get_extension) include("../ext/FixedPointNumbersStatisticsExt.jl") end -if VERSION >= v"1.1" # work around https://github.com/JuliaLang/julia/issues/34121 - include("precompile.jl") - _precompile_() -end +include("precompile.jl") +_precompile_() end # module diff --git a/src/fixed.jl b/src/fixed.jl index 212a95ff..2a3971d8 100644 --- a/src/fixed.jl +++ b/src/fixed.jl @@ -50,7 +50,7 @@ fracmask(x::Fixed{T,f}) where {T, f} = ~intmask(x) # Signed # constructor-style conversions function _convert(::Type{F}, x::Fixed{T2,f2}) where {T, T2, f, f2, F <: Fixed{T,f}} - y = round(@exp2(f-f2) * reinterpret(x)) + y = round(exp2(f-f2) * reinterpret(x)) (typemin(T) <= y) & (y <= typemax(T)) || throw_converterror(F, x) reinterpret(F, _unsafe_trunc(T, y)) end @@ -65,10 +65,10 @@ end function _convert(::Type{F}, x::AbstractFloat) where {T, f, F <: Fixed{T,f}} bigx = big(x) - bmin = BigFloat(typemin(F)) - @exp2(-f-1) - bmax = BigFloat(typemax(F)) + @exp2(-f-1) + bmin = BigFloat(typemin(F)) - exp2(-f-1) + bmax = BigFloat(typemax(F)) + exp2(-f-1) if bmin <= bigx < bmax - reinterpret(F, round(T, bigx * @exp2(f))) + reinterpret(F, round(T, bigx * exp2(f))) else throw_converterror(F, x) end @@ -78,8 +78,8 @@ _convert(::Type{F}, x::Float16) where {T, f, F <: Fixed{T,f}} = F(Float32(x)) function _convert(::Type{F}, x::Union{Float32, Float64}) where {T, f, F <: Fixed{T,f}} Tf = typeof(x) - if Tf(typemin(F) - @exp2(-f-1)) <= x < Tf(typemax(F) + @exp2(-f-1)) - reinterpret(F, round(T, x * @exp2(f))) + if Tf(typemin(F) - exp2(-f-1)) <= x < Tf(typemax(F) + exp2(-f-1)) + reinterpret(F, round(T, x * exp2(f))) else throw_converterror(F, x) end @@ -89,7 +89,7 @@ function _convert(::Type{F}, x::Rational) where {T, f, F <: Fixed{T,f}} xmin = widemul(denominator(x), widen1(T)(typemin(T)) << 0x1 - 0x1) xmax = widemul(denominator(x), oneunit(widen1(T)) << bitwidth(T) - 0x1) if xmin <= (widen1(numerator(x)) << UInt8(f + 1)) < xmax - reinterpret(F, round(T, convert(floattype(T), x) * @exp2(f))) + reinterpret(F, round(T, convert(floattype(T), x) * exp2(f))) else throw_converterror(F, x) end @@ -98,7 +98,7 @@ end _rem(x::F, ::Type{F}) where {F <: Fixed} = x function _rem(x::Fixed, ::Type{F}) where {T, f, F <: Fixed{T,f}} f2 = nbitsfrac(typeof(x)) - y = round(@exp2(f - f2) * reinterpret(x)) + y = round(exp2(f - f2) * reinterpret(x)) reinterpret(F, _unsafe_trunc(T, y)) end _rem(x::Integer, ::Type{F}) where {T, f, F <: Fixed{T,f}} = F(_unsafe_trunc(T, x) << f, 0) @@ -110,18 +110,18 @@ function _rem(x::Real, ::Type{F}) where {T, f, F <: Fixed{T,f}} Ti = promote_type(Int64, T) end Tf = floattype(F) - y = _unsafe_trunc(Ti, round(x * Tf(@exp2(f)))) + y = _unsafe_trunc(Ti, round(x * Tf(exp2(f)))) reinterpret(F, _unsafe_trunc(T, y)) end function _rem(x::BigFloat, ::Type{F}) where {T, f, F <: Fixed{T,f}} isfinite(x) || return zero(F) - reinterpret(F, _unsafe_trunc(T, round(x * @exp2(f)))) + reinterpret(F, _unsafe_trunc(T, round(x * exp2(f)))) end -(::Type{Tf})(x::Fixed{T,f}) where {Tf <: AbstractFloat, T, f} = Tf(Tf(x.i) * Tf(@exp2(-f))) +(::Type{Tf})(x::Fixed{T,f}) where {Tf <: AbstractFloat, T, f} = Tf(Tf(x.i) * Tf(exp2(-f))) Base.Float16(x::Fixed{T,f}) where {T, f} = Float16(Float32(x)) -Base.Float32(x::Fixed{T,f}) where {T, f} = Float32(x.i) * Float32(@exp2(-f)) -Base.Float64(x::Fixed{T,f}) where {T, f} = Float64(x.i) * @exp2(-f) +Base.Float32(x::Fixed{T,f}) where {T, f} = Float32(x.i) * Float32(exp2(-f)) +Base.Float64(x::Fixed{T,f}) where {T, f} = Float64(x.i) * exp2(-f) function Base.Rational(x::Fixed{T,f}) where {T, f} f < bitwidth(T)-1 ? x.i//rawone(x) : x.i//(one(widen1(T))<>> 0x1 lower = intmask(x) >> 0x1 if f == bitwidth(T) - 1 - x.i > upper && throw_converterror(Fixed{T,f}, @exp2(bitwidth(T)-f-1)) + x.i > upper && throw_converterror(Fixed{T,f}, exp2(bitwidth(T)-f-1)) return x.i < lower ? typemin(x) : zero(x) end - x.i >= upper && throw_converterror(Fixed{T,f}, @exp2(bitwidth(T)-f-1)) + x.i >= upper && throw_converterror(Fixed{T,f}, exp2(bitwidth(T)-f-1)) y = oneunit(T) << UInt8(f - 1) + x.i m = oneunit(T) << UInt8(f + 1) - oneunit(T) z = y & intmask(x) @@ -223,7 +223,7 @@ function _round_digits(x::F, r::RoundingMode, d::Int) where {f, F <: Fixed{Int8, else xr = r isa RoundingMode{:Up} ? (xd + fracmask(x)) >> uf : div_2f(xd, Val(Int(f))) if d < 3 && xr == (Int16(d === 1 ? 10 : 100) << (0x7 - uf)) - throw_converterror(F, @exp2(7 - f)) + throw_converterror(F, exp2(7 - f)) end end h8, h24 = Int16(0x80), Int32(1 << 23) diff --git a/src/normed.jl b/src/normed.jl index 7bc7e87d..f3931ba9 100644 --- a/src/normed.jl +++ b/src/normed.jl @@ -179,7 +179,7 @@ function Base.Float32(x::Normed{UInt32,f}) where f return muladd(rh, @f32(0x1p-16), rl * @f32(0x1p-40)) elseif f >= 25 rh, rl = Float32(i32>>>0x10), Float32((i32&0xFFFF)<<0xE + i32>>>UInt8(f-14)) - return muladd(rh, Float32(@exp2(16-f)), rl * Float32(@exp2(-14-f))) + return muladd(rh, Float32(exp2(16-f)), rl * Float32(exp2(-14-f))) end # FIXME: avoid the branch in native x86_64 (non-SIMD) codes m = ifelse(i32 < 0, 0x1p32 * inv_rawone(x), 0.0) @@ -225,24 +225,24 @@ end function Base.Float64(x::Normed{UInt64,f}) where f f == 1 && return Float64(x.i) if f >= 53 - rh = Float64(unsafe_trunc(Int64, x.i>>0x10)) * @exp2(16-f) # upper 48 bits - rl = Float64(unsafe_trunc(Int32, x.i&0xFFFF)) * @exp2(-f) # lower 16 bits - return rh + muladd(rh, @exp2(-f), rl) + rh = Float64(unsafe_trunc(Int64, x.i>>0x10)) * exp2(16-f) # upper 48 bits + rl = Float64(unsafe_trunc(Int32, x.i&0xFFFF)) * exp2(-f) # lower 16 bits + return rh + muladd(rh, exp2(-f), rl) end x.i / rawone(x) end function Base.Float64(x::Normed{UInt128,f}) where f f == 1 && return Float64(x.i) ih, il = unsafe_trunc(Int64, x.i>>0x40), unsafe_trunc(Int64, x.i) - rh = Float64(ih>>>0x10) * @exp2(f <= 53 ? 80 : 80 - f) # upper 48 bits - km = @exp2(f <= 53 ? 48 : 48 - f) # for middle 32 bits + rh = Float64(ih>>>0x10) * exp2(f <= 53 ? 80 : 80 - f) # upper 48 bits + km = exp2(f <= 53 ? 48 : 48 - f) # for middle 32 bits rm = Float64(unsafe_trunc(Int32, ih&0xFFFF)) * (0x1p16 * km) + Float64(unsafe_trunc(Int32, il>>>0x30)) * km - rl = Float64(il&0xFFFFFFFFFFFF) * @exp2(f <= 53 ? 0 : -f) # lower 48 bits + rl = Float64(il&0xFFFFFFFFFFFF) * exp2(f <= 53 ? 0 : -f) # lower 48 bits if f <= 53 return (rh + (rm + rl)) / unsafe_trunc(Int64, rawone(x)) elseif f < 76 - return rh + (rm + muladd(rh, @exp2(-f), rl)) + return rh + (rm + muladd(rh, exp2(-f), rl)) else return rh + (rm + rl) end diff --git a/src/utilities.jl b/src/utilities.jl index cb7650da..0ee4cfe2 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -26,10 +26,6 @@ const UShorterThanInt = typeintersect(ShorterThanInt, Unsigned) macro f32(x::Float64) # just for hexadecimal floating-point literals :(Float32($x)) end -macro exp2(n) - :(_exp2(Val($(esc(n))))) -end -_exp2(::Val{N}) where {N} = exp2(N) # these are defined in julia/float.jl or julia/math.jl, but not exported significand_bits(::Type{Float32}) = 23 diff --git a/test/common.jl b/test/common.jl index 32b4eeb2..36c723ae 100644 --- a/test/common.jl +++ b/test/common.jl @@ -2,8 +2,6 @@ using FixedPointNumbers, Statistics, Random, StableRNGs, Test using FixedPointNumbers: bitwidth, rawtype, nbitsfrac using Base.Checked -SP = VERSION >= v"1.6.0-DEV.771" ? " " : "" # JuliaLang/julia #37085 - """ target(X::Type, Ss...; ex = :default) @@ -399,10 +397,10 @@ end function test_sign_related(TX::Type) for X in target(TX, :i8; ex = :thin) # `FixedPoint` is not a signed or unsigned integer type - @test_throws Exception signed(X) - @test_throws Exception signed(X(0.5)) - @test_throws Exception unsigned(X) - @test_throws Exception unsigned(X(0.5)) + @test_throws MethodError signed(X) + @test_throws MethodError signed(X(0.5)) + @test_throws MethodError unsigned(X) + @test_throws MethodError unsigned(X(0.5)) @test sign(X(0.0)) === zero(X) if typemax(X) >= 1.0 diff --git a/test/fixed.jl b/test/fixed.jl index 55520d7a..c1ea4b98 100644 --- a/test/fixed.jl +++ b/test/fixed.jl @@ -172,7 +172,7 @@ end @test occursin("Q0f7 is an 8-bit type representing 256 values from -1.0 to 0.992;", msg) ret = @test_throws ArgumentError convert(Fixed{Int128,100}, 10.0^9) msg = ret.value.msg - @test occursin("Fixed{Int128,$(SP)100} is a 128-bit type representing 2^128 values", msg) + @test occursin("Fixed{Int128, 100} is a 128-bit type representing 2^128 values", msg) end @testset "disambiguation constructors" begin @@ -811,24 +811,18 @@ end @test String(take!(iob)) == "-21845.33334Q15f16" show(iob, Fixed{Int128,64}(-1.2345e6)) - @test String(take!(iob)) == "Fixed{Int128,$(SP)64}(-1.2345e6)" + @test String(take!(iob)) == "Fixed{Int128, 64}(-1.2345e6)" # TODO: remove this test show(iob, reinterpret(Fixed{Int8,8}, signed(0xaa))) - @test String(take!(iob)) == "Fixed{Int8,$(SP)8}(-0.336)" + @test String(take!(iob)) == "Fixed{Int8, 8}(-0.336)" end @testset "summary" begin a = Q0f7[0.2, 0.4] aa = Fixed[0.2Q0f7 0.4Q0f15] - if VERSION >= v"1.6.0-DEV.356" - @test summary(a) == "2-element Vector{Q0f7}" - @test summary(view(a, 1:2)) == "2-element view(::Vector{Q0f7}, 1:2) with eltype Q0f7" - @test summary(aa) == "1×2 Matrix{Fixed}" - else - @test summary(a) == "2-element Array{Q0f7,1} with eltype Fixed{Int8,7}" - @test summary(view(a, 1:2)) == "2-element view(::Array{Q0f7,1}, 1:2) with eltype Fixed{Int8,7}" - @test summary(aa) == "1×2 Array{Fixed,2}" - end + @test summary(a) == "2-element Vector{Q0f7}" + @test summary(view(a, 1:2)) == "2-element view(::Vector{Q0f7}, 1:2) with eltype Q0f7" + @test summary(aa) == "1×2 Matrix{Fixed}" end diff --git a/test/normed.jl b/test/normed.jl index 1221c2fe..70e32d3a 100644 --- a/test/normed.jl +++ b/test/normed.jl @@ -116,7 +116,7 @@ end @test occursin("N0f8 is an 8-bit type representing 256 values from 0.0 to 1.0;", msg) ret = @test_throws ArgumentError convert(Normed{UInt128,100}, 10.0^9) msg = ret.value.msg - @test occursin("Normed{UInt128,$(SP)100} is a 128-bit type representing 2^128 values", msg) + @test occursin("Normed{UInt128, 100} is a 128-bit type representing 2^128 values", msg) end @testset "disambiguation constructors" begin @@ -232,7 +232,6 @@ end end input_upper = Tf(BigFloat(typemax(T)) / r, RoundDown) - isinf(input_upper) && continue # for Julia v0.7 @test reinterpret(N(input_upper)) == T(min(round(BigFloat(input_upper) * r), typemax(T))) input_exp2 = Tf(exp2(bitwidth(T) - f)) @@ -788,22 +787,16 @@ end @test String(take!(iob)) == "43691.33333N16f16" show(iob, Normed{UInt128,64}(1.2345e6)) - @test String(take!(iob)) == "Normed{UInt128,$(SP)64}(1.2345e6)" + @test String(take!(iob)) == "Normed{UInt128, 64}(1.2345e6)" end @testset "summary" begin a = N0f8[0.2, 0.4] aa = Normed[0.2N0f8 0.4N0f16] - if VERSION >= v"1.6.0-DEV.356" - @test summary(a) == "2-element Vector{N0f8}" - @test summary(view(a, 1:2)) == "2-element view(::Vector{N0f8}, 1:2) with eltype N0f8" - @test summary(aa) == "1×2 Matrix{Normed}" - else - @test summary(a) == "2-element Array{N0f8,1} with eltype Normed{UInt8,8}" - @test summary(view(a, 1:2)) == "2-element view(::Array{N0f8,1}, 1:2) with eltype Normed{UInt8,8}" - @test summary(aa) == "1×2 Array{Normed,2}" - end + @test summary(a) == "2-element Vector{N0f8}" + @test summary(view(a, 1:2)) == "2-element view(::Vector{N0f8}, 1:2) with eltype N0f8" + @test summary(aa) == "1×2 Matrix{Normed}" end @testset "scaledual" begin