-
Notifications
You must be signed in to change notification settings - Fork 112
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
Support fma (fused multiply-add) #31
Conversation
This looks great, and I really appreciate your efforts to improve ranges. Even better that some of this functionality will be available on 0.5! Before merging, I wanted to bring your attention to a problem I've encountered, which seems like it will be relevant here. For this PR, the problem is not limiting, so I'm willing to push through this PR and leave an open issue regarding promotion, if you'd like. This is a larger problem though, appearing also in #24 regarding The problem is that because quantities have different types for different units and dimensions, promoting fails to return a common type if you promote quantities of differing dimensions. If you try and do One idea I had would be to have a values-based (rather than type-based) quantity as a fallback, which could represent any units or dimensions in one type, at the expense of run-time penalties. This way, I could guarantee that promotion could always yield a common type (type-based quantities could be promoted to value-based quantities if there were no other option). Obviously I don't like the idea of sacrificing performance to get |
On second thought it's not really as if the problem I'm describing is worth holding this up, so I'll just merge it. At least you're aware of the issue now. |
I've noticed this as a problem, too. Perhaps we need to use the following design: foo{T}(a::T, b::T) = # the real method, i.e., the one that implements the computation
foo(a, b) = _foo(promote(a, b)...)
_foo{T}(a::T, b::T) = foo(a, b) # promotion worked
_foo(a, b) = error("promotion of $a and $b failed to produce a common type") |
I can certainly implement that design pattern in Unitful for your |
Can you submit a julia PR? If not, I'll do it (eventually). |
I'll add that to my list, but do let me know if I'm taking too long and you want to take care of it instead... having some build problems with Julia on macOS Sierra that I need to figure out. Please see here, lines 590–625, for a proposed change to your |
Having learned my lesson about submitting julia PRs prematurely some months ago, I thought some more and I think I may be able to get fastmath working without one. In trying to get around an existing method in base like this (e.g. line 241 of fastmath.jl):
It seems you can write these methods, with no dispatch ambiguity:
Method (1) would only be called when passing two arguments, neither of which are Anyway, thanks for humoring me, I'll stop bothering you now 😅 |
Cool github trick: navigate to the page containing the code you want to link to, select the range of line numbers you want to highlight (you can use the shift key), hit the 'y' key on your keyboard (this inserts the current commit sha into the url, making it a "permalink" even as the code evolves), and then copy paste the url into a discussion page. The one issue I see with the |
With regards to eliminating runtime checking: you can either wait until we get triangular dispatch (julia 0.6, see JuliaLang/julia#18457) or do stuff like this: _fma{T<:Quantity}(x, y::T, z::T) = _fma_dimension(x, dimension(x), y, z)
_fma_dimension(x, ::Dimension{()}, y, z) = fma(x, y, z)
_fma_dimension(x, ::Dimension, y, z) = throw(DimensionError()) The general trick is to add arguments that "peel out" the things you need to examine, then use dispatch to direct the execution to either error messages or computation. All this gets inlined by the compiler, so (unlike the runtime checks) it doesn't have any negative impact on performance. |
Thank you for the tips! Some follow-up questions:
|
Alright, what I'm specifically confused about is the following. Using
Whereas with my implementation in the
Even more surprisingly, this doesn't appear to have a run-time check either:
So I don't think they are doing run-time checks, despite appearances...? |
Hey, if the compiler is eliding them, great! Much easier this way. |
Alright, so fma is maybe 90% working, but I can't devote any more time to this right now; seemingly small changes to the code (to me anyway) gave pretty different llvm outputs, and I kept hitting method ambiguities. You may want to checkout master and test for yourself that you're satisfied. I tried to avoid regressing on the method you implemented, since I presume it is the most important case for you. runtests.jl gives some indication of where I saw problems and where llvm output was "good" or "bad." Unless you're using dimensionless quantities a lot you shouldn't run into trouble, at least on julia 0.5.0. With a view on future changes: This has been very interesting to see the limits of promotion as I've currently implemented it. I think one problem is that |
In trying to use this for various real world applications, I finally got tired of not having decent ranges. The result was JuliaLang/julia#18777, for which
fma
support seems likely to be important.I also have a package brewing so we can use this on 0.5.