| //===--- MathFunctions.swift ----------------------------------*- swift -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2019 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| import SwiftShims |
| |
| %from SwiftMathFunctions import * |
| %from SwiftFloatingPointTypes import all_floating_point_types |
| |
| %# Skip `Float16` for now until it's clear how to conform it to |
| %# `ElementaryFunctions`, i.e. after apple/swift-numerics adds the conformance. |
| %floating_point_types = [type for type in all_floating_point_types() if type.bits != 16] |
| |
| /// A type that has elementary functions available. |
| /// |
| /// An ["elementary function"][elfn] is a function built up from powers, roots, |
| /// exponentials, logarithms, trigonometric functions (sin, cos, tan) and |
| /// their inverses, and the hyperbolic functions (sinh, cosh, tanh) and their |
| /// inverses. |
| /// |
| /// Conformance to this protocol means that all of these building blocks are |
| /// available as static functions on the type. |
| /// |
| /// ```swift |
| /// let x: Float = 1 |
| /// let y = Float.sin(x) // 0.84147096 |
| /// ``` |
| /// |
| /// [elfn]: http://en.wikipedia.org/wiki/Elementary_function |
| // SWIFT_ENABLE_TENSORFLOW |
| // NOTE(TF-796): Make `ElementaryFunctions` available on macOS. |
| // @available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) |
| public protocol ElementaryFunctions { |
| |
| %for func in ElementaryFunctions: |
| |
| ${func.comment} |
| static func ${func.decl("Self")} |
| %end |
| |
| /// `exp(y log(x))` computed without loss of intermediate precision. |
| /// |
| /// For real types, if `x` is negative the result is NaN, even if `y` has |
| /// an integral value. For complex types, there is a branch cut on the |
| /// negative real axis. |
| static func pow(_ x: Self, _ y: Self) -> Self |
| |
| /// `x` raised to the `n`th power. |
| static func pow(_ x: Self, _ n: Int) -> Self |
| |
| /// The `n`th root of `x`. |
| /// |
| /// For real types, if `x` is negative and `n` is even, the result is NaN. |
| /// For complex types, there is a branch cut along the negative real axis. |
| static func root(_ x: Self, _ n: Int) -> Self |
| } |
| |
| %for type in floating_point_types: |
| % if type.bits == 80: |
| #if (arch(i386) || arch(x86_64)) && !(os(Windows) || os(Android)) |
| % end |
| % Self = type.stdlib_name |
| extension ${Self}: ElementaryFunctions { |
| % for func in ElementaryFunctions + RealFunctions: |
| |
| @_alwaysEmitIntoClient |
| public static func ${func.decl(Self)} { |
| return ${func.impl(type)} |
| } |
| % end |
| |
| @_alwaysEmitIntoClient |
| public static func pow(_ x: ${Self}, _ y: ${Self}) -> ${Self} { |
| guard x >= 0 else { return .nan } |
| return ${Self}(Builtin.int_pow_FPIEEE${type.bits}(x._value, y._value)) |
| } |
| |
| @_alwaysEmitIntoClient |
| public static func pow(_ x: ${Self}, _ n: Int) -> ${Self} { |
| // TODO: this implementation isn't quite right for n so large that |
| // the conversion to `${Self}` rounds. We could also consider using |
| // a multiply-chain implementation for small `n`; this would be faster |
| // for static `n`, but less accurate on platforms with a good `pow` |
| // implementation. |
| return ${Self}(Builtin.int_pow_FPIEEE${type.bits}(x._value, ${Self}(n)._value)) |
| } |
| |
| @_alwaysEmitIntoClient |
| public static func root(_ x: ${Self}, _ n: Int) -> ${Self} { |
| guard x >= 0 || n % 2 != 0 else { return .nan } |
| // TODO: this implementation isn't quite right for n so large that |
| // the conversion to `${Self}` rounds. |
| return ${Self}(signOf: x, magnitudeOf: pow(x.magnitude, 1/${Self}(n))) |
| } |
| |
| @_alwaysEmitIntoClient |
| public static func atan2(_ y: ${Self}, _ x: ${Self}) -> ${Self} { |
| return _stdlib_atan2${type.cFuncSuffix}(y, x) |
| } |
| |
| #if !os(Windows) |
| @_alwaysEmitIntoClient |
| public static func logGamma(_ x: ${Self}) -> ${Self} { |
| return _stdlib_lgamma${type.cFuncSuffix}(x) |
| } |
| |
| @_alwaysEmitIntoClient |
| public static func signGamma(_ x: ${Self}) -> FloatingPointSign { |
| if x >= 0 { return .plus } |
| let trunc = x.rounded(.towardZero) |
| if x == trunc { return .plus } |
| let halfTrunc = trunc/2 |
| if halfTrunc == halfTrunc.rounded(.towardZero) { return .minus } |
| return .plus |
| } |
| #endif |
| } |
| % if type.bits == 80: |
| #endif |
| % end |
| %end |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // NOTE(TF-796): Make `ElementaryFunctions` available on macOS. |
| // @available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) |
| extension SIMD where Scalar: ElementaryFunctions { |
| % for func in ElementaryFunctions: |
| |
| @_alwaysEmitIntoClient |
| public static func ${func.decl("Self")} { |
| var r = Self() |
| for i in r.indices { |
| r[i] = Scalar.${func.swiftName}(${func.params(suffix="[i]")}) |
| } |
| return r |
| } |
| % end |
| |
| @_alwaysEmitIntoClient |
| public static func pow(_ x: Self, _ y: Self) -> Self { |
| var r = Self() |
| for i in r.indices { |
| r[i] = Scalar.pow(x[i], y[i]) |
| } |
| return r |
| } |
| |
| @_alwaysEmitIntoClient |
| public static func pow(_ x: Self, _ n: Int) -> Self { |
| var r = Self() |
| for i in r.indices { |
| r[i] = Scalar.pow(x[i], n) |
| } |
| return r |
| } |
| |
| @_alwaysEmitIntoClient |
| public static func root(_ x: Self, _ n: Int) -> Self { |
| var r = Self() |
| for i in r.indices { |
| r[i] = Scalar.root(x[i], n) |
| } |
| return r |
| } |
| } |
| |
| %for n in [2,3,4,8,16,32,64]: |
| // SWIFT_ENABLE_TENSORFLOW |
| // NOTE(TF-796): Make `ElementaryFunctions` available on macOS. |
| // @available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) |
| extension SIMD${n}: ElementaryFunctions where Scalar: ElementaryFunctions { } |
| %end |