Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix isinteger #123

Closed
wants to merge 10 commits into from
Closed

fix isinteger #123

wants to merge 10 commits into from

Conversation

johnnychen94
Copy link
Collaborator

fixes #120 : isinteger(1N0f8) should be true

P.S. I don't quite understand the magic behind bits operation, but the tests pass with this patch.

cc: @cjdoris

fixes JuliaMath#120 : `isinteger(1N0f8)` should be true
@codecov-io
Copy link

codecov-io commented May 15, 2019

Codecov Report

Merging #123 into master will increase coverage by 0.1%.
The diff coverage is 100%.

Impacted file tree graph

@@           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
Impacted Files Coverage Δ
src/normed.jl 80.64% <100%> (+0.21%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5729a89...5cf20d5. Read the comment docs.

test/fixed.jl Outdated Show resolved Hide resolved
@johnnychen94
Copy link
Collaborator Author

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):

  • make generate_fixedpoint_types a test utils
  • fix isinteger

@johnnychen94
Copy link
Collaborator Author

johnnychen94 commented May 16, 2019

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?

Copy link
Collaborator

@kimikage kimikage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

Comment on lines +1 to +18
""" 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)))
end

I believe that any exceptions do not occur in unbroken modules. If any exceptions should occur, they should not be caught.

Comment on lines +173 to +174
# predicates
isinteger(x::Normed{T,f}) where {T,f} = (x.i%(1<<f-1)) == 0
Copy link
Collaborator

@kimikage kimikage Oct 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also comment for the Fixed test.
isinteger(x::Normed{T,f}) where {T,f} = (x.i%(one(T)<<f-1)) == 0
Edit:

Suggested change
# 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:

# predicates
isinteger(x::FixedPoint{T,f}) where {T,f} = (x.i&(1<<f-1)) == 0

And then, add isinteger(x::Fixed{T,f}) where {T,f} = (x.i&(one(T)<<f-0x1)) == 0 into "src/fixed.jl"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above is analogous to isinteger(x::Fixed). Of course, you can use rawone(Normed{T,f}).

Comment on lines +149 to +157
@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
Copy link
Collaborator

@kimikage kimikage Oct 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for the failures on 32-bit systems is that the bit mask is only 32-bit length even for Fixed{Int64}.

isinteger(x::FixedPoint{T,f}) where {T,f} = (x.i&(1<<f-1)) == 0

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)) == 0

BTW, 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.

Comment on lines +348 to +356
@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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the comment for Fixed version.

@johnnychen94
Copy link
Collaborator Author

johnnychen94 commented Oct 12, 2019

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)

@kimikage
Copy link
Collaborator

As I did not care about this issue until yesterday, please take your time.

@kimikage
Copy link
Collaborator

I am sorry for hindering the rebase, but now we can use isinteger(x) == isinteger(float(x)) to test Normed{UInt8}, Normed{UInt16} and Fixed.
However, float(x::Normed{UInt32}) and float(x::Normed{UInt64}) still have 1-lsb errors. If you want to introduce the random testing for them, extra checks are required.
IMO, the implementation of isinteger should be so primitive that only the numbers around the boundaries which might possibly cause overflow/underflow should be checked.

@kimikage
Copy link
Collaborator

I'm ready to fix isinteger with minimal tests (i.e. without random tests).
kimikage/FixedPointNumbers.jl@commonize1...kimikage:isinteger

Since the master has left this branch, I'm going to submit a new PR.

@johnnychen94
Copy link
Collaborator Author

@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.

@kimikage kimikage mentioned this pull request Jan 12, 2020
@johnnychen94 johnnychen94 deleted the isinteger branch January 12, 2020 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

isinteger(::Normed) incorrect
4 participants