-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
group ccall'ed MPZ library functions in a module #21654
Conversation
base/gmp.jl
Outdated
@@ -69,6 +69,93 @@ function __init__() | |||
end | |||
end | |||
|
|||
|
|||
module mpz |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modules names should be in all caps (if an acronym) or upper camel case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I'm sensible to that, but I made this choice to be as close as possible to the original function names, of the form "mpz_add", which translates here into "mpz.add". An alternative could be to not have any submodule and to name the julia functions as in GMP, with the "mpz_" prefix. I prefer the module with lower case, and I thought that an exception to the style can be made as it's an internal sub-sub-module of Base. But will change if you or someone insists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would rather stick with the established naming conventions. I don't think it's especially necessary to have julia wrappers for C functions use exactly the same names as in the C library, when the conventions or meanings for names differ in idiomatic Julia
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, most importantly because the convention can easily lead one to believe when perusing the code that mpz
is an object rather than a module, which is quite confusing. So I think that writing MPZ.add
would be less likely to be confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I got convinced :) thanks for your input.
This is cool! @nanosoldier |
base/gmp.jl
Outdated
end | ||
|
||
invert(x::BigInt, a::BigInt, b::BigInt) = | ||
ccall((:__gmpz_invert, :libgmp), Cint, (Ptr{BigInt}, Ptr{BigInt}, Ptr{BigInt}), &x, &a, &b) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is getting updated might as well update the &
syntax , since it is deprecated and should be using the Ref{T}
argument type instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it still has a performance cost though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will as well then wait till the performances get on par...
@nanosoldier |
@ararslan thanks, your nanosoldier run didn't work probably because I had a forgotten |
@rfourquet You need commit access to trigger nanosoldier (maybe you already have access, but that's my guess as to why nothing happened here, since everything looks fine server side). @nanosoldier |
Weird, nothing's happening here even though the logs server-side seem fine. I kicked Nanosoldier, let's try again: @nanosoldier |
Your benchmark job has completed, but no benchmarks were actually executed. Perhaps your tag predicate contains mispelled tags? cc @jrevels |
Benchmarks do exist with those keys, but keys weren't counted as tags in BenchmarkTools until v0.0.8, and Nanosoldier only had v0.0.7. Just did a @nanosoldier |
Your benchmark job has completed - no performance regressions were detected. A full report can be found here. cc @jrevels |
Thanks @jrevels ! Rerunning with "Complex{BigInt}", as it seems "Complex" is not enough to handle it. |
@nanosoldier |
Your benchmark job has completed - no performance regressions were detected. A full report can be found here. cc @jrevels |
base/gmp.jl
Outdated
|
||
for op in (:add, :sub, :mul, :fdiv_q, :tdiv_q, :fdiv_r, :tdiv_r, :gcd, :lcm, :and, :ior, :xor) | ||
@eval begin | ||
$op(x::BigInt, a::BigInt, b::BigInt) = (ccall($(gmpz(op)), Void, (Ptr{BigInt}, Ptr{BigInt}, Ptr{BigInt}), &x, &a, &b); x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should get a !
since it is mutating the input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your review. I hesitated about that, but prefered to follow as closely as possible the original names (from GMP). Am fine to change though; according to their previous comments on the case of the module name, I guess @tkelman and @StefanKarpinski would agree with you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is also the "problem" that since we are extending Base.gcd
, there will also be a method gcd(::BigInt, ::BigInt, ::BigInt)
exposed to the user, which does funny things from a user perspective. In particular it is breaking the following behaviour:
julia> gcd(BigInt(3), BigInt(2), BigInt(4))
1
With the proposed change the function mutates the first argument and returns 2
.
I don't think this is what we want and gcd
is not the only function with this problem.
Edit: Sorry, my mistake. This does not break anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes you are right, though it is mitigated by the fact that Base.gcd
is not touched here, we introduce only a hard-to-find Base.GMP.MPZ.gcd
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, you are right. Overlooked the MPZ module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@StefanKarpinski and @tkelman, could you comment on this? I kept the names as in libgmp without any !
even for mutating functions (and for few functions I added a variant with a !
when updating the input, like add!(x, y) = add(x, x, y)
, equivalent to a x += y
), which seems more predictable for me, but @thofma suggests to add !
whenever an argument is modified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Julia wrapper functions should try to aim for following idiomatic Julia naming/argument conventions whenever possible, rather than matching C API naming exactly (if you want to be calling the C API directly, you can always use ccall yourself). We have a bit of an unfortunate mix of these styles at the moment, I have a few of the library binding files on my personal to-do list to clean up in this way and be more consistent about. Disparate C libraries aren't going to have any common conventions, but would be nice if our bindings attempted to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you again for your extended answer, I will update accordingly.
base/gmp.jl
Outdated
|
||
for op in (:add_ui, :sub_ui, :mul_ui, :mul_2exp, :fdiv_q_2exp, :pow_ui, :bin_ui) | ||
@eval begin | ||
$op(x::BigInt, a::BigInt, b) = (ccall($(gmpz(op)), Void, (Ptr{BigInt}, Ptr{BigInt}, Culong), &x, &a, b); x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!
base/gmp.jl
Outdated
end | ||
end | ||
|
||
ui_sub(x::BigInt, a, b::BigInt) = (ccall((:__gmpz_ui_sub, :libgmp), Void, (Ptr{BigInt}, Culong, Ptr{BigInt}), &x, a, &b); x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!
base/gmp.jl
Outdated
|
||
for op in (:neg, :com, :sqrt, :set) | ||
@eval begin | ||
$op(x::BigInt, a::BigInt) = (ccall($(gmpz(op)), Void, (Ptr{BigInt}, Ptr{BigInt}), &x, &a); x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!
base/gmp.jl
Outdated
|
||
popcount(a::BigInt) = Int(ccall((:__gmpz_popcount, :libgmp), Culong, (Ptr{BigInt},), &a)) | ||
|
||
function tdiv_qr(x::BigInt, y::BigInt, a::BigInt, b::BigInt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!
There are more functions missing a |
44c6719
to
662439a
Compare
I updated by renaming functions with a |
This looks good to me (I made one trivial edit to a comment) - these look like they would be handy for writing in-place BigInt code. Let's run @nanosoldier |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @jrevels |
Thanks. Indeed working on in-place |
What's the difference between mpz and mpn in libgmp? Hard to keep track of their naming convention if you don't use the low-level library calls that often. There's no problem with packages writing extended library bindings to libraries that are for now shipped by default with Julia (see for example BandedMatrices.jl which has some lapack bindings that aren't all that useful within base), but the eventual plan is probably to separate out the library-specific bindings from the bare-minimum BigInt type definition, and make the former optional or swappable (if we ever care more about MSVC we may want to try out MPIR instead of libgmp for example). |
The MPN functions are lower level than MPZ: MPZ tries to provide a convenient application-level user interface, while MPN provides low-level routines taking raw arrays as input instead of |
I added a forgotten binding used in the |
Thanks for this nice PR. I use the inplace version of Would it be sufficient to copy all the code between |
Thanks! I had not realized this change was not in 0.6. It should be pretty trivial to backport to 0.6, indeed by copying all the code in the |
Thanks for your help. Everything seems to work indeed by just copying the MPZ module, even without any change. I would indeed think that licenses are compatible, so I'll take my chance and register the package including a copy of your MPZ module, if that's fine by you. When Julia 0.7 or 1.0 is released, I'll probably drop 0.6 support. |
The goals where 1) making the code cleaner in the implementation of julia function (so that it's not full of difficult-to-read
ccall
s), and 2) avoid duplication for for some of theccall
, within base itself, but also for users/packages.With the help of some functions which create automatically new
BigInt
objects for output arguments, the simplification in 1) has gone beyond my expectation :) The same could probably be done in mpfr.jl.