blob: 67b9735b7a77a1acf9ac31b715fa2322ac5707a6 [file] [log] [blame]
//===--- 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