<div dir="ltr"><div>A math library should include vectorized operations as part of its vector type support; i currently use <a href="https://gist.github.com/kelvin13/03d1fd5da024f058b6fd38fdbce665a4">this snippet</a> to cover that. Even though they are evaluated as scalars right now, if simd/sse support ever comes to Linux it’ll be easy to switch to it since all the vectorizable operations are already routed through the “vector” functions. <br></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Aug 3, 2017 at 5:03 PM, Nicolas Fezans <span dir="ltr"><<a href="mailto:nicolas.fezans@gmail.com" target="_blank">nicolas.fezans@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Interesting figures. I will not try to discuss the generics, inlineable, etc. there are certainly good observations and comments to make here, but most people in this list know certainly more about it than I do.<div><br></div><div>I just want to point out that IMO a core math library for swift should comply with the IEEE 754 standard in terms of precision, domain, and special values. <u>On the long term</u>, it should ideally be able to use SIMD instructions when applied to arrays/matrices or when the compiler can autovectorize some loops.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Aug 3, 2017 at 8:52 PM, Taylor Swift via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div>In an effort to get this thread back on track, I tried implementing cos(_:) in pure generic Swift code, with the BinaryFloatingPoint protocol. It deviates from the _cos(_:) intrinsic by no more than 5.26362703423544e-11. Adding more terms to the approximation only has a small penalty to the performance for some reason.<br><br></div>To make the benchmarks fair, and explore the idea of distributing a Math module without killing people on the cross-module optimization boundary, I enabled some of the unsafe compiler attributes. All of these benchmarks are cross-module calls, as if the math module were downloaded as a dependency in the SPM.<br><br><span style="font-family:monospace,monospace">== Relative execution time (lower is better) ==<br><br></span><span style="font-family:monospace,monospace"><span style="background-color:rgb(217,210,233)">llvm intrinsic : 3.133</span><br></span></div><div><span style="font-family:monospace,monospace"><span style="background-color:rgb(234,209,220)">glibc cos() : 3.124</span><br></span></div><div><span style="font-family:monospace,monospace"><br>no attributes : 43.675<br>with specialization : 4.162<br>with inlining : 3.108<br>with inlining and specialization : 3.264</span><br><br></div>As you can see, the pure Swift generic implementation actually beats the compiler intrinsic (and the glibc cos() but I guess they’re the same thing) when inlining is used, but for some reason generic specialization and inlining don’t get along very well.<br><br></div>Here’s the source implementation. It uses a taylor series (!) which probably isn’t optimal but it does prove that cos() and sin() can be implemented as generics in pure Swift, be distributed as a module outside the stdlib, and still achieve competitive performance with the llvm intrinsics.<br><br><span style="font-family:monospace,monospace">@_inlineable<br>//@_specialize(where F == Float)<br>//@_specialize(where F == Double)<br>public<br>func cos<F>(_ x:F) -> F where F:BinaryFloatingPoint<br>{<br> let x:F = abs(x.remainder(dividingBy: 2 * F.pi)),<br> quadrant:Int = Int(x * (2 / F.pi))<br><br> switch quadrant<br> {<br> case 0:<br> return cos(on_first_quadrant: x)<br> case 1:<br> return -cos(on_first_quadrant: F.pi - x)<br> case 2:<br> return -cos(on_first_quadrant: x - F.pi)<br> case 3:<br> return -cos(on_first_quadrant: 2 * F.pi - x)<br> default:<br> fatalError("unreachable")<br> }<br>}<br><br>@_versioned<br>@_inlineable<br>//@_specialize(where F == Float)<br>//@_specialize(where F == Double)<br>func cos<F>(on_first_quadrant x:F) -> F where F:BinaryFloatingPoint<br>{<br> let x2:F = x * x<br> var y:F = -0.000000000011470745126775543<wbr>2394<br> for c:F in [0.000000002087675698165412591<wbr>559,<br> -0.000000275573192239332256421<wbr>489,<br> 0.0000248015873015870233004515<wbr>7,<br> -0.001388888888888888803101864<wbr>15,<br> 0.0416666666666666666531941198<wbr>8,<br> -0.499999999999999999999163743<wbr>7,<br> 0.9999999999999999999999914771<br> ]<br> {<br> y = x2 * y + c<br> }<br> return y<br>}</span><br></div><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="m_-7932268330397119791h5">On Thu, Aug 3, 2017 at 7:04 AM, Stephen Canon via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="m_-7932268330397119791h5"><div style="word-wrap:break-word;line-break:after-white-space"><span><blockquote type="cite">On Aug 2, 2017, at 7:03 PM, Karl Wagner via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:<br></blockquote><div><blockquote type="cite"><div><br class="m_-7932268330397119791m_-8088712979627551895m_3712668855384799923Apple-interchange-newline"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">It’s important to remember that computers are mathematical machines, and some functions which are implemented in hardware on essentially every platform (like sin/cos/etc) are definitely best implemented as compiler intrinsics.</span></div></blockquote><br></div></span><div>sin/cos/etc are implemented in software, not hardware. x86 does have the FSIN/FCOS instructions, but (almost) no one actually uses them to implement the sin( ) and cos( ) functions; they are a legacy curiosity, both too slow and too inaccurate for serious use today. There are no analogous instructions on ARM or PPC.</div><div><br></div><div>– Steve</div></div><br></div></div><span>______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br>
<br></span></blockquote></div><br></div>
<br>______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br>
<br></blockquote></div><br></div>
</blockquote></div><br></div>