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

Improve exponent function #19512

Merged
merged 2 commits into from
Dec 8, 2016
Merged

Improve exponent function #19512

merged 2 commits into from
Dec 8, 2016

Conversation

musm
Copy link
Contributor

@musm musm commented Dec 5, 2016

Remove unnecessary branch/better perf

julia> @code_llvm my_exponent(-10.1)

; Function Attrs: uwtable
define i64 @julia__exponent_72099(double) #0 {
top:
  %1 = bitcast double %0 to i64
  %2 = and i64 %1, 9223372036854775807
  %3 = icmp ult i64 %2, 9218868437227405312
  br i1 %3, label %pass, label %if

L2:                                               ; preds = %pass.8, %pass
  %k.0 = phi i64 [ %5, %pass ], [ %9, %pass.8 ]
  %4 = add nsw i64 %k.0, -1023
  ret i64 %4

if:                                               ; preds = %top
  call void @jl_throw(%jl_value_t* inttoptr (i64 2153013112 to %jl_value_t*))
  unreachable

pass:                                             ; preds = %top
  %5 = lshr i64 %2, 52
  %6 = icmp ugt i64 %2, 4503599627370495
  br i1 %6, label %L2, label %if3

if3:                                              ; preds = %pass
  %7 = icmp eq i64 %2, 0
  br i1 %7, label %if4, label %pass.8

if4:                                              ; preds = %if3
  call void @jl_throw(%jl_value_t* inttoptr (i64 2153013112 to %jl_value_t*))
  unreachable

pass.8:                                           ; preds = %if3
  %8 = call i64 @llvm.ctlz.i64(i64 %2, i1 false)
  %9 = sub nsw i64 12, %8
  br label %L2
}

julia> @code_llvm exponent(-10.1)



; Function Attrs: uwtable
define i64 @julia_exponent_72000(double) #0 {
pass:
  %1 = bitcast double %0 to i64
  %2 = and i64 %1, 9218868437227405312
  %3 = icmp eq i64 %2, 0
  br i1 %3, label %if, label %L1

L1:                                               ; preds = %pass
  %4 = lshr exact i64 %2, 52
  %5 = icmp eq i64 %2, 9218868437227405312
  br i1 %5, label %if6, label %L2

L2:                                               ; preds = %L1, %pass.5
  %k.0 = phi i64 [ %4, %L1 ], [ %10, %pass.5 ]
  %6 = add nsw i64 %k.0, -1023
  ret i64 %6

if:                                               ; preds = %pass
  %7 = fcmp une double %0, 0.000000e+00
  br i1 %7, label %pass.5, label %if3

if3:                                              ; preds = %if
  call void @jl_throw(%jl_value_t* inttoptr (i64 2153013112 to %jl_value_t*))
  unreachable

pass.5:                                           ; preds = %if
  %8 = and i64 %1, 4503599627370495
  %9 = call i64 @llvm.ctlz.i64(i64 %8, i1 false)
  %10 = sub nsw i64 12, %9
  br label %L2

if6:                                              ; preds = %L1
  call void @jl_throw(%jl_value_t* inttoptr (i64 2153013112 to %jl_value_t*))
  unreachable

@musm
Copy link
Contributor Author

musm commented Dec 5, 2016

What about changing this function to behave as follows (i.e. like ilog2, under certain error flag)

and thus things like this actually work

x = Inf
ldexp(significand(x), ilog2(x)) # ldexp(significand(x), exponent(x)), or w/e you wanna call it

returns 
Inf
    ilog2(x)

Returns the integral part of the logarithm of `abs(x)`, using base 2 for the
logarithm. In other words, this computes the binary exponent of `x` such that
``x = significand \\times 2^exponent,`` where ``significand∈\\in [1, 2)``.

Exceptional cases (where `Int` is the machine wordsize)

* `x = 0`    returns `typemin(Int)`
* `x = ±Inf` returns `typemax(Int)`
* `x = NaN`  returns `typemax(Int)`

@oscardssmith
Copy link
Member

the behavior for inf and nan seem dangerous to me, couldn't that cause all sorts of corruption?

@musm
Copy link
Contributor Author

musm commented Dec 6, 2016

Which are you referring to?

@oscardssmith
Copy link
Member

x = ±Inf returns typemax(Int)
x = NaN returns typemax(Int)
These could hide buggy code and cause all sort of problems.

@musm
Copy link
Contributor Author

musm commented Dec 6, 2016

Perhaps this should be a separate issue as it is independent of the PR, which just improves the current behavior.

xs = reinterpret(Unsigned, x) & ~sign_mask(T)
xs >= exponent_mask(T) && return throw(DomainError()) # NaN or Inf
k = Int(xs >> significand_bits(T))
if xs <= (~exponent_mask(T) & ~sign_mask(T)) # x is subnormal
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be better to just do if k == 0? (comparisons vs values that are representable by Int32 can sometimes be faster)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yea here and for frexp is doesn't matter, I chose consistency with the significand function. See #19492
If you prefer I can change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok I made the chnage here and to frexp

@simonbyrne
Copy link
Contributor

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

@simonbyrne simonbyrne added the maths Mathematical functions label Dec 7, 2016
@nanosoldier
Copy link
Collaborator

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

@simonbyrne simonbyrne merged commit 6e0b762 into JuliaLang:master Dec 8, 2016
@musm
Copy link
Contributor Author

musm commented Dec 8, 2016

thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maths Mathematical functions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants