//===--- 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 /// 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 /// ``` /// /// Additional operations, such as `atan2(y:x:)`, `hypot(_:_:)` and some /// special functions, are provided on the Real protocol, which refines both /// ElementaryFunctions and FloatingPoint. /// /// [elfn]: http://en.wikipedia.org/wiki/Elementary_function 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 } /// A type that models the real numbers. /// /// Conformance to this protocol means that all the FloatingPoint operations /// are available, as well as the ElementaryFunctions, plus the following /// additional math functions: atan2, erf, erc, hypot, tgamma. /// /// logGamma and signGamma are also available on non-Windows platforms. public protocol Real: ElementaryFunctions, FloatingPoint { %for func in RealFunctions: ${func.comment} static func ${func.decl("Self")} %end /// `atan(y/x)` with quadrant fixup. /// /// There is an infinite family of angles whose tangent is `y/x`. `atan2` /// selects the representative that is the angle between the vector `(x, y)` /// and the real axis in the range [-π, π]. static func atan2(y: Self, x: Self) -> Self #if !os(Windows) // lgamma is not available on Windows. // TODO: provide an implementation of lgamma with the stdlib to support // Windows so we can vend a uniform interface. /// `log(gamma(x))` computed without undue overflow. /// /// `log(abs(gamma(x)))` is returned. To get the sign of `gamma(x)` cheaply, /// use `signGamma(x)`. static func logGamma(_ x: Self) -> Self #endif } extension Real { #if !os(Windows) // lgamma is not available on Windows; no lgamma means signGamma // is basically useless, so don't bother exposing it. /// The sign of `gamma(x)`. /// /// This function is typically used in conjunction with `logGamma(x)`, which /// computes `log(abs(gamma(x)))`, to recover the sign information that is /// lost to the absolute value. /// /// `gamma(x)` has a simple pole at each non-positive integer and an /// essential singularity at infinity; we arbitrarily choose to return /// `.plus` for the sign in those cases. For all other values, `signGamma(x)` /// is `.plus` if `x >= 0` or `trunc(x)` is odd, and `.minus` otherwise. @_alwaysEmitIntoClient public static func signGamma(_ x: Self) -> FloatingPointSign { if x >= 0 { return .plus } let trunc = x.rounded(.towardZero) // Treat poles as gamma(x) == +inf. This is arbitrary, but we need to // pick one sign or the other. if x == trunc { return .plus } // Result is .minus if trunc is even, .plus otherwise. To figure out if // trunc is even or odd, check if trunc/2 is an integer. let halfTrunc = trunc/2 if halfTrunc == halfTrunc.rounded(.towardZero) { return .minus } return .plus } #endif } %for type in all_floating_point_types(): % if type.bits == 80: #if (arch(i386) || arch(x86_64)) && !os(Windows) % end % Self = type.stdlib_name extension ${Self}: Real { % 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, 1/${Self}(n))) } @_alwaysEmitIntoClient public static func atan2(y: ${Self}, x: ${Self}) -> ${Self} { return _swift_stdlib_atan2${type.cFuncSuffix}(y, x) } #if !os(Windows) @_alwaysEmitIntoClient public static func logGamma(_ x: ${Self}) -> ${Self} { return _swift_stdlib_lgamma${type.cFuncSuffix}(x) } #endif } % if type.bits == 80: #endif % end %end