Conversation
fixes JuliaMath#120 : `isinteger(1N0f8)` should be true
Codecov Report
@@ Coverage Diff @@
## master #123 +/- ##
========================================
+ Coverage 78.3% 78.4% +0.1%
========================================
Files 3 3
Lines 212 213 +1
========================================
+ Hits 166 167 +1
Misses 46 46
Continue to review full report at Codecov.
|
This helps improve test type coverage
|
After solving the conflicts, I failed to rebase the commits (not a git expert). You could either squash it or rebase it into two commits (if it's possible):
|
|
Wow, this patch fails in Windows x86. That's really out of my ability then. Can someone take it over to let the test pass? |
There was a problem hiding this comment.
@johnnychen94, please replace the 1<<f-1 with one(T)<<f-0x1.
(Don't forget to restore the CI settings.:smile:)
Edit:
I'm sorry, but the suggestions were wrong. Now fixed.
| """ return true if symbol `x` is a `ST` type""" | ||
| function _is_type(x::Symbol, ST::Symbol) | ||
| try | ||
| @eval $(x) isa Type && $(x) <: $(ST) && return true | ||
| catch | ||
| return false | ||
| end | ||
| end | ||
|
|
||
| """ | ||
| generate_fixedpoint_types(ST::Symbol=:FixedPoint) | ||
|
|
||
| generate a list of concrete `ST` types, where `ST ∈ (:FixedPoint, :Fixed, :Normed)` | ||
| """ | ||
| function generate_fixedpoint_types(ST::Symbol=:FixedPoint) | ||
| fixed_types = setdiff(filter(x->_is_type(x, ST), names(FixedPointNumbers)), [:Fixed, :Normed, :FixedPoint]) | ||
| fixed_types = [@eval $(x) for x in fixed_types] | ||
| end |
There was a problem hiding this comment.
What about using isconcretetype(T) instead of setdiff and renaming this function to something like concrete_subtypes.
"""
concrete_subtypes(T::Type)
generate a list of concrete subtypes of `T` which are defined in `FixedPointNumbers`.
"""
function concrete_subtypes(T::Type)
is_concrete_subtype(x) = x isa Type && x <: T && isconcretetype(x)
filter(is_concrete_subtype, eval.(names(FixedPointNumbers)))
endI believe that any exceptions do not occur in unbroken modules. If any exceptions should occur, they should not be caught.
| # predicates | ||
| isinteger(x::Normed{T,f}) where {T,f} = (x.i%(1<<f-1)) == 0 |
There was a problem hiding this comment.
See also comment for the Fixed test.
isinteger(x::Normed{T,f}) where {T,f} = (x.i%(one(T)<<f-1)) == 0
Edit:
| # predicates | |
| isinteger(x::Normed{T,f}) where {T,f} = (x.i%(1<<f-1)) == 0 | |
| isinteger(x::Normed{T,f}) where {T,f} = (x.i%(one(T)<<f-0x1)) == 0 |
FYI, (n%-1) == 0 is always true.
Moreover, if you write this here (I think we should do so), we should remove the following:
FixedPointNumbers.jl/src/FixedPointNumbers.jl
Lines 56 to 57 in da39318
And then, add
isinteger(x::Fixed{T,f}) where {T,f} = (x.i&(one(T)<<f-0x1)) == 0 into "src/fixed.jl"
There was a problem hiding this comment.
The above is analogous to isinteger(x::Fixed). Of course, you can use rawone(Normed{T,f}).
| @testset "isinteger" begin | ||
| # issue #120 | ||
| for T in generate_fixedpoint_types(:Fixed) | ||
| T_ints = T.(clamp.(rand(rawtype(T), 500, 500), | ||
| ceil(rawtype(T), floattype(T)(typemin(T))), | ||
| floor(rawtype(T), floattype(T)(typemax(T))))) | ||
| @test all(isinteger.(T_ints)) | ||
| end | ||
| end |
There was a problem hiding this comment.
The reason for the failures on 32-bit systems is that the bit mask is only 32-bit length even for Fixed{Int64}.
julia> typeof(1)
Int32
julia> typeof(1<<63)
Int32
julia> bitstring(1<<63-1)
"11111111111111111111111111111111"
julia> bitstring(one(Int64)<<63-1)
"0111111111111111111111111111111111111111111111111111111111111111"Therefore, we should fix it up as follows:
isinteger(x::Fixed{T,f}) where {T,f} = (x.i&(one(T)<<f-0x1)) == 0BTW, since this is a testset for Fixed, not Image, we do not have to store such a large matrix.
There are only 65,536(=256×256 < 500×500) different patterns for each Fixed{Int16} type. So, for Fixed{Int16} and Fixed{Int8} types, @timholy's method is better. (There is no round() for Fixed, though.) I think it is important to check the non-integer cases.
In addition, the types with a large f can represent only few integers (e.g. two integers: -1Q0f31 and 0Q0f31). I think this is too inefficient.
| @testset "isinteger" begin | ||
| # issue #120 | ||
| for T in generate_fixedpoint_types(:Normed) | ||
| T_ints = T.(clamp.(rand(rawtype(T), 500, 500), | ||
| ceil(rawtype(T), floattype(T)(typemin(T))), | ||
| floor(rawtype(T), floattype(T)(typemax(T))))) | ||
| @test all(isinteger.(T_ints)) | ||
| end | ||
| end |
There was a problem hiding this comment.
See the comment for Fixed version.
|
Thank you for putting your time investigating it! I'll find time to fix them accordingly. (I'm a little busy these days, and my night time is spent on ReferenceTests.jl, so if you can't wait, you can continue the work here :D) |
|
As I did not care about this issue until yesterday, please take your time. |
|
I am sorry for hindering the |
|
I'm ready to fix Since the master has left this branch, I'm going to submit a new PR. |
|
@kimikage Please feel free to do so 👍 , recently I just spent too much time here and I'm trying to catch up with my daily research projects in ECNU. |
fixes #120 :
isinteger(1N0f8)should be trueP.S. I don't quite understand the magic behind bits operation, but the tests pass with this patch.
cc: @cjdoris