Skip to content

Conversation

@musm
Copy link
Contributor

@musm musm commented Oct 18, 2016

We can get rid of the custom Float16 handling of this and have all isinf be hardware independent.

Same thing with isnan ....

base/float.jl Outdated
isfinite(x::Integer) = true

isinf(x::Real) = !isnan(x) & !isfinite(x)
isinf(x::Real) = (reinterpret(Unsigned, x) & ~sign_mask(T)) == exponent_mask(T)
Copy link
Member

Choose a reason for hiding this comment

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

This is fine for specific floating-point formats (Float16, Float32, Float64) but not ok for generic Reals. I would leave the existing method for Real and add a more specific method for those types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, I'll do that.

Copy link
Member

Choose a reason for hiding this comment

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

Perhaps we also need an extra IEEEFloat abstract type, for which these things are valid?

Copy link
Contributor Author

@musm musm Oct 18, 2016

Choose a reason for hiding this comment

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

@vchuravy has been using IntrinsicFloats
Either sound reasonable.

Copy link
Member

Choose a reason for hiding this comment

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

I like IEEEFloat, and will use it instead of my IntrinsicFloats.

@musm musm changed the title Is inf hardware indep isinf hardware indep Oct 18, 2016
@musm musm closed this Oct 18, 2016
@musm musm reopened this Oct 18, 2016
@musm
Copy link
Contributor Author

musm commented Oct 19, 2016

Sounds good for the IEEEFloat alias, updated PR with isinf, isnan, and isfinite

Copy link
Member

@vchuravy vchuravy left a comment

Choose a reason for hiding this comment

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

Do we have benchmarks for this?

isinf{T<:IEEEFloat}(x::T) = (reinterpret(Unsigned, x) & ~sign_mask(T)) == exponent_mask(T)
isinf(x::Real) = !isnan(x) & !isfinite(x)


Copy link
Member

Choose a reason for hiding this comment

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

unnecessary newline

Test whether a floating point number is not a number (NaN).
"""
isnan{T<:IEEEFloat}(x::T) = (reinterpret(Unsigned, x) & ~sign_mask(T)) > exponent_mask(T)
Copy link
Member

Choose a reason for hiding this comment

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

Cool did not know reinterpret(Unsigned, x) is a thing.

Copy link
Member

Choose a reason for hiding this comment

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

Is this more efficient than x != x?

Copy link
Contributor

@p-zubieta p-zubieta Oct 19, 2016

Choose a reason for hiding this comment

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

It is not

# x != x
julia> @code_native isnan(NaN)
    .text
Filename: float.jl
    pushq   %rbp
    movq    %rsp, %rbp
Source line: 355
    ucomisd %xmm0, %xmm0
    setp    %al
    popq    %rbp
    retq
    nopl    (%rax)

# This PR
julia> @code_native isnan2(NaN)
    .text
Filename: REPL[3]
    pushq   %rbp
    movq    %rsp, %rbp
Source line: 1
    movd    %xmm0, %rax
    movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
    andq    %rax, %rcx
    movabsq $9218868437227405312, %rax # imm = 0x7FF0000000000000
    cmpq    %rax, %rcx
    seta    %al
    popq    %rbp
    retq
    nopl    (%rax,%rax)

I don't think we should sacrifice losing this hardware instructions when available.

Copy link
Contributor Author

@musm musm Oct 19, 2016

Choose a reason for hiding this comment

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

See https://gist.github.com/musm/8150451b04120ef27974d8270dedbf6f
for more comprehensive tests (the gist is we are comparing performance in the 10-100 picosecond range...) So basically these instructions are so cheap and fast that it really doesn't matter on modern processors. In other words, the changes are just as fast as what we already have.

For isnan I agree, unfortunately we still require special handling for Float16 which prompted this pr, which I thought would be good to unify all the exceptional case handling to be independent of floating point hardware instructions so that Float16 (F128/F80) would be handled all the same. But the problem currently is that cpu support for small floats is not great (but I think now intel is investing more on this side due to demand).

I'll leave this to @vchuravy expertise on the issue on whether these proposed changes are positive or not, for now I am closing this.

For the denormals even though x - x will not work. It's only on the x87 chips where exceptional handling are very bad (some x87 sandybridge too?), where one may want to disable or flush them to zero.

But disabling denormals is not recommended, so the issue will probably never crop up; someone would have to go out of their way to disable them in Julia anyways.

So perhaps only for isinf and isfinite the changes are positive, but at that point might as well just use what we already have.

@vchuravy
Copy link
Member

It seems we do have benchmarks https://github.com/JuliaCI/BaseBenchmarks.jl/blob/0e13bcd0e14337cfb6f6513a1d3d04b468b2abaa/src/scalar/ScalarBenchmarks.jl#L14, even though we should probably bench Float16 too

@nanosoldier runbenchmarks(ALL, vs=":master")

isnan(x::Real) = false

"""
isfinite(f) -> Bool
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be removed from helpdb/Base.jl if it's also there and now duplicated?

Test whether a floating point number is an infinity value (positive infinity or negative infinity).
"""
isinf{T<:IEEEFloat}(x::T) = (reinterpret(Unsigned, x) & ~sign_mask(T)) == exponent_mask(T)
Copy link
Member

Choose a reason for hiding this comment

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

Again, is this more efficient?

@nanosoldier
Copy link
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @jrevels

@musm
Copy link
Contributor Author

musm commented Oct 19, 2016

@vchuravy How meaningful is to benchmark changes that are within a fraction of a nanosecond?
The current base version may translate differently when compiled for another platform. x - x may fail for cpus with disabled subnormal support.

Apparently master branch of BenchmarkTools is now reliable to within ns range (but perhaps nanosoldier is not yet using the master branch).

See: https://gist.github.com/musm/8150451b04120ef27974d8270dedbf6f

@vchuravy
Copy link
Member

I think Nanosoldier might still not use nanosecond resolution. Nevertheless changes to these kinds of function can have effects throughout the whole codebase
The regressions that nanosoldier is seeing are to big to be noise so it might be worthwhile seeing what the difference is.

@nalimilan
Copy link
Member

The current base version may translate differently when compiled for another platform. x - x may fail for cpus with disabled subnormal support.

Would be good to have actual examples of such CPUs before making this method more complex.

@musm
Copy link
Contributor Author

musm commented Oct 19, 2016

right, I highly doubt the second point...unless perhaps some ancient cpu that julia doesn't work on :)

@jrevels
Copy link
Member

jrevels commented Oct 19, 2016

Just to clarify: BenchmarkTools/Nanosoldier has always had nanosecond resolution, so if that's what you require here, you've already got it. A recent PR has given BenchmarkTools picosecond resolution, but that hasn't been tagged/released yet because it breaks JLD (de)serialization compatibility with old data (i.e. all the data in BaseBenchmarkReports).

@musm
Copy link
Contributor Author

musm commented Oct 19, 2016

@jrevels On the tagged version of BenchmarkTools the benchmark results are all stuck at 3ns it's only when I use the master version I obtain perceptible differences. It's likely that ns resolution is not enough here.

@musm musm closed this Oct 19, 2016
@vchuravy
Copy link
Member

@musm Thank you for the effort you put into this. I will most likely do parts of this in #18927

@musm musm changed the title isinf hardware indep hardware independent isinf/isnan/isfinite Oct 20, 2016
@musm musm deleted the isinf branch April 24, 2017 19:03
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.

9 participants