[swift-evolution] TrigonometricFloatingPoint/MathFloatingPoint protocol?

Taylor Swift kelvin13ma at gmail.com
Thu Aug 3 18:21:20 CDT 2017


On Thu, Aug 3, 2017 at 7:17 PM, Karl Wagner <razielim at gmail.com> wrote:

>
> On 3. Aug 2017, at 20:52, Taylor Swift via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> 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.
>
> 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.
>
> == Relative execution time (lower is better) ==
>
> llvm intrinsic                   :  3.133
> glibc cos()                      :  3.124
>
> no attributes                    : 43.675
> with specialization              :  4.162
> with inlining                    :  3.108
> with inlining and specialization :  3.264
>
> 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.
>
> 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.
>
> @_inlineable
> //@_specialize(where F == Float)
> //@_specialize(where F == Double)
> public
> func cos<F>(_ x:F) -> F where F:BinaryFloatingPoint
> {
>     let x:F = abs(x.remainder(dividingBy: 2 * F.pi)),
>         quadrant:Int = Int(x * (2 / F.pi))
>
>     switch quadrant
>     {
>     case 0:
>         return  cos(on_first_quadrant:        x)
>     case 1:
>         return -cos(on_first_quadrant: F.pi - x)
>     case 2:
>         return -cos(on_first_quadrant: x - F.pi)
>     case 3:
>         return -cos(on_first_quadrant: 2 * F.pi - x)
>     default:
>         fatalError("unreachable")
>     }
> }
>
> @_versioned
> @_inlineable
> //@_specialize(where F == Float)
> //@_specialize(where F == Double)
> func cos<F>(on_first_quadrant x:F) -> F where F:BinaryFloatingPoint
> {
>     let x2:F = x * x
>     var y:F  = -0.0000000000114707451267755432394
>     for c:F in [0.000000002087675698165412591559,
>                -0.000000275573192239332256421489,
>                 0.00002480158730158702330045157,
>                -0.00138888888888888880310186415,
>                 0.04166666666666666665319411988,
>                -0.4999999999999999999991637437,
>                 0.9999999999999999999999914771
>                 ]
>     {
>         y = x2 * y + c
>     }
>     return y
> }
>
> On Thu, Aug 3, 2017 at 7:04 AM, Stephen Canon via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> On Aug 2, 2017, at 7:03 PM, Karl Wagner via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>>
>> 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.
>>
>>
>> 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.
>>
>> – Steve
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> Just a guess, but I’d expect inlining implies specialisation. It would be
> weird if the compiler inlined a chunk of unoptimised generic code in to
> your function.
>
> Pretty cool figures, though.
>
> - Karl
>
>
The weird part is that generic specialization actually *hurt* performance.
I understand why inlining can be harmful sometimes, but I always assumed
specialization was always helpful. Weird. Can a core team member weigh in
here?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170803/6bdbcd79/attachment.html>


More information about the swift-evolution mailing list