623 lines
13 KiB
Swift
623 lines
13 KiB
Swift
//
|
|
// Real.swift
|
|
// NumericAnnex
|
|
//
|
|
// Created by Xiaodi Wu on 4/1/17.
|
|
//
|
|
|
|
#if os(Linux)
|
|
import Glibc
|
|
#else
|
|
import Darwin.C
|
|
#endif
|
|
|
|
/// A floating-point type that supports elementary functions and a selection of
|
|
/// special functions.
|
|
///
|
|
/// The `Real` protocol provides a suitable basis for writing functions that
|
|
/// work on any floating-point type that supports the required functions.
|
|
public protocol Real : Math, FloatingPoint {
|
|
/// Returns the hypotenuse of a right-angle triangle with legs (catheti) of
|
|
/// length `x` and `y`, preventing avoidable arithmetic overflow and
|
|
/// underflow. The return value is the square root of the sum of squares of
|
|
/// the arguments.
|
|
///
|
|
/// - Parameters:
|
|
/// - x: The length of one leg (cathetus) of a right-angle triangle.
|
|
/// - y: The length of the other leg (cathetus) of a right-angle triangle.
|
|
static func hypot(_ x: Self, _ y: Self) -> Self
|
|
|
|
/// Returns the inverse tangent of `self / other`, using the signs of `self`
|
|
/// and `other` to determine the quadrant of the computed angle.
|
|
///
|
|
/// If `self == 0 && other == 0`, the return value is still finite.
|
|
///
|
|
/// - Parameters:
|
|
/// - other: The divisor by which to divide `self`.
|
|
///
|
|
/// - SeeAlso: `atan2(_:_:)`
|
|
func inverseTangent(dividingBy other: Self) -> Self
|
|
|
|
/// Returns the value of the [error function][dfn] of `self`.
|
|
///
|
|
/// [dfn]: http://mathworld.wolfram.com/Erf.html
|
|
///
|
|
/// - SeeAlso: `erf(_:)`
|
|
func error() -> Self
|
|
|
|
/// Returns the value of the [complementary error function][dfn] of `self`.
|
|
///
|
|
/// [dfn]: http://mathworld.wolfram.com/Erfc.html
|
|
///
|
|
/// - SeeAlso: `erfc(_:)`
|
|
func complementaryError() -> Self
|
|
|
|
/// Returns the value of the [gamma function][dfn] of `self`.
|
|
///
|
|
/// [dfn]: http://mathworld.wolfram.com/GammaFunction.html
|
|
///
|
|
/// - SeeAlso: `tgamma(_:)`
|
|
func gamma() -> Self
|
|
|
|
/// Returns the value of the [logarithmic gamma function][dfn] of `self`.
|
|
///
|
|
/// [dfn]: http://mathworld.wolfram.com/LogGammaFunction.html
|
|
///
|
|
/// - SeeAlso: `lgamma(_:)`
|
|
func logarithmicGamma() -> Self
|
|
|
|
// FIXME: Design and implement `logarithmicGammaAndSignOfGamma()`.
|
|
|
|
// FIXME: If corresponding requirements are added to FloatingPoint
|
|
// add init<U : SignedInteger>(_: Rational<U>) as well as
|
|
// init?<U : SignedInteger>(exactly: Rational<U>).
|
|
}
|
|
|
|
extension Real {
|
|
public static func hypot(_ x: Self, _ y: Self) -> Self {
|
|
var x = abs(x), y = abs(y)
|
|
if x.isInfinite { return x }
|
|
if y.isInfinite { return y }
|
|
if x == 0 { return y }
|
|
if x < y { swap(&x, &y) }
|
|
let ratio = y / x
|
|
return x * .sqrt(1 + ratio * ratio)
|
|
}
|
|
|
|
/// Returns the cube root of the value, rounded to a representable value
|
|
/// (default implementation).
|
|
///
|
|
/// - Note: This method is required by the protocol `Math`; it is not an
|
|
/// extension method.
|
|
///
|
|
/// - SeeAlso: `cbrt(_:)`
|
|
public func cubeRoot() -> Self {
|
|
return sign == .minus ? -.exp(.log(-self) / 3) : .exp(.log(self) / 3)
|
|
}
|
|
|
|
public func inverseTangent(dividingBy other: Self) -> Self {
|
|
let y = self, x = other
|
|
if y.isInfinite {
|
|
if x.isInfinite {
|
|
switch (y.sign, x.sign) {
|
|
case (.minus, .minus): return -.pi * 3 / 4
|
|
case (.plus, .minus): return .pi * 3 / 4
|
|
case (.minus, .plus): return -.pi / 4
|
|
case (.plus, .plus): return .pi / 4
|
|
}
|
|
}
|
|
return y.sign == .minus ? -.pi / 2 : .pi / 2
|
|
}
|
|
if x > 0 {
|
|
return 2 * .atan(y / (.sqrt(x * x + y * y) + x))
|
|
}
|
|
if y != 0 {
|
|
return 2 * .atan((.sqrt(x * x + y * y) - x) / y)
|
|
}
|
|
if x.sign == .minus /* && y == 0 */ {
|
|
return y.sign == .minus ? -.pi : .pi
|
|
}
|
|
/* x.sign == .plus && y == 0 */
|
|
return y.sign == .minus ? -(0 as Self) : 0
|
|
}
|
|
}
|
|
|
|
extension Real {
|
|
/// Returns the inverse tangent of `y / x`, using the signs of `y` and `x` to
|
|
/// determine the quadrant of the computed angle.
|
|
///
|
|
/// If `x == 0 && y == 0`, the return value is still finite.
|
|
///
|
|
/// - Parameters:
|
|
/// - y: The value to divide.
|
|
/// - x: The divisor by which to divide `y`.
|
|
///
|
|
/// - SeeAlso: `inverseTangent(dividingBy:)`
|
|
@_transparent // @_inlineable
|
|
public static func atan2(_ y: Self, _ x: Self) -> Self {
|
|
// Note the order of the internal names `y` and `x`, which is deliberate: a
|
|
// minority of programming languages vend functions that reverse the order
|
|
// of the arguments, but all refer to the denominator as `x` and the
|
|
// numerator as `y`.
|
|
return y.inverseTangent(dividingBy: x)
|
|
}
|
|
|
|
/// Returns the value of the [error function][dfn] of `x`.
|
|
///
|
|
/// [dfn]: http://mathworld.wolfram.com/Erf.html
|
|
///
|
|
/// - SeeAlso: `error()`
|
|
@_transparent // @_inlineable
|
|
public static func erf(_ x: Self) -> Self {
|
|
return x.error()
|
|
}
|
|
|
|
/// Returns the value of the [complementary error function][dfn] of `x`.
|
|
///
|
|
/// [dfn]: http://mathworld.wolfram.com/Erfc.html
|
|
///
|
|
/// - SeeAlso: `complementaryError()`
|
|
@_transparent // @_inlineable
|
|
public static func erfc(_ x: Self) -> Self {
|
|
return x.complementaryError()
|
|
}
|
|
|
|
/// Returns the value of the [gamma function][dfn] of `x`.
|
|
///
|
|
/// [dfn]: http://mathworld.wolfram.com/GammaFunction.html
|
|
///
|
|
/// - SeeAlso: `gamma()`
|
|
@_transparent // @_inlineable
|
|
public static func tgamma(_ x: Self) -> Self {
|
|
return x.gamma()
|
|
}
|
|
|
|
/// Returns the value of the [logarithmic gamma function][dfn] of `x`.
|
|
///
|
|
/// [dfn]: http://mathworld.wolfram.com/LogGammaFunction.html
|
|
///
|
|
/// - SeeAlso: `logarithmicGamma()`
|
|
@_transparent // @_inlineable
|
|
public static func lgamma(_ x: Self) -> Self {
|
|
return x.logarithmicGamma()
|
|
}
|
|
}
|
|
|
|
extension Float : Real {
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Real
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@_transparent
|
|
public static var e: Float {
|
|
return Float(0x1.5bf0a8p1)
|
|
}
|
|
|
|
@_transparent
|
|
public static var phi: Float {
|
|
return Float(0x1.9e377ap0)
|
|
}
|
|
|
|
@_transparent
|
|
public static func ** (lhs: Float, rhs: Float) -> Float {
|
|
return powf(lhs, rhs)
|
|
}
|
|
|
|
@_transparent
|
|
public static func **= (lhs: inout Float, rhs: Float) {
|
|
lhs = lhs ** rhs
|
|
}
|
|
|
|
@_transparent
|
|
public func naturalExponential() -> Float {
|
|
return expf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func binaryExponential() -> Float {
|
|
return exp2f(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func commonExponential() -> Float {
|
|
#if os(Linux)
|
|
return exp10f(self)
|
|
#else
|
|
return __exp10f(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func naturalExponentialMinusOne() -> Float {
|
|
return expm1f(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func naturalLogarithm() -> Float {
|
|
return logf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func binaryLogarithm() -> Float {
|
|
return log2f(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func commonLogarithm() -> Float {
|
|
return log10f(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func naturalLogarithmOnePlus() -> Float {
|
|
return log1pf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func cubeRoot() -> Float {
|
|
return cbrtf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func sine() -> Float {
|
|
return sinf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func cosine() -> Float {
|
|
return cosf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func tangent() -> Float {
|
|
return tanf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseSine() -> Float {
|
|
return asinf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseCosine() -> Float {
|
|
return acosf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseTangent() -> Float {
|
|
return atanf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func hyperbolicSine() -> Float {
|
|
return sinhf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func hyperbolicCosine() -> Float {
|
|
return coshf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func hyperbolicTangent() -> Float {
|
|
return tanhf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseHyperbolicSine() -> Float {
|
|
return asinhf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseHyperbolicCosine() -> Float {
|
|
return acoshf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseHyperbolicTangent() -> Float {
|
|
return atanhf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public static func hypot(_ x: Float, _ y: Float) -> Float {
|
|
return hypotf(x, y)
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseTangent(dividingBy other: Float) -> Float {
|
|
return atan2f(self, other)
|
|
}
|
|
|
|
@_transparent
|
|
public func error() -> Float {
|
|
return erff(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func complementaryError() -> Float {
|
|
return erfcf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func gamma() -> Float {
|
|
return tgammaf(self)
|
|
}
|
|
|
|
@_transparent
|
|
public func logarithmicGamma() -> Float {
|
|
return lgammaf(self)
|
|
}
|
|
}
|
|
|
|
extension Double : Real {
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Real
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@_transparent
|
|
public static var e: Double {
|
|
return Double(0x1.5bf0a8b145769p1)
|
|
}
|
|
|
|
@_transparent
|
|
public static var phi: Double {
|
|
return Double(0x1.9e3779b97f4a8p0)
|
|
}
|
|
|
|
@_transparent
|
|
public static func ** (lhs: Double, rhs: Double) -> Double {
|
|
#if os(Linux)
|
|
return Glibc.pow(lhs, rhs)
|
|
#else
|
|
return Darwin.pow(lhs, rhs)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public static func **= (lhs: inout Double, rhs: Double) {
|
|
lhs = lhs ** rhs
|
|
}
|
|
|
|
@_transparent
|
|
public func naturalExponential() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.exp(self)
|
|
#else
|
|
return Darwin.exp(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func binaryExponential() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.exp2(self)
|
|
#else
|
|
return Darwin.exp2(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func commonExponential() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.exp10(self)
|
|
#else
|
|
return __exp10(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func naturalExponentialMinusOne() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.expm1(self)
|
|
#else
|
|
return Darwin.expm1(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func naturalLogarithm() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.log(self)
|
|
#else
|
|
return Darwin.log(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func binaryLogarithm() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.log2(self)
|
|
#else
|
|
return Darwin.log2(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func commonLogarithm() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.log10(self)
|
|
#else
|
|
return Darwin.log10(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func naturalLogarithmOnePlus() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.log1p(self)
|
|
#else
|
|
return Darwin.log1p(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func cubeRoot() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.cbrt(self)
|
|
#else
|
|
return Darwin.cbrt(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func sine() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.sin(self)
|
|
#else
|
|
return Darwin.sin(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func cosine() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.cos(self)
|
|
#else
|
|
return Darwin.cos(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func tangent() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.tan(self)
|
|
#else
|
|
return Darwin.tan(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseSine() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.asin(self)
|
|
#else
|
|
return Darwin.asin(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseCosine() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.acos(self)
|
|
#else
|
|
return Darwin.acos(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseTangent() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.atan(self)
|
|
#else
|
|
return Darwin.atan(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func hyperbolicSine() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.sinh(self)
|
|
#else
|
|
return Darwin.sinh(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func hyperbolicCosine() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.cosh(self)
|
|
#else
|
|
return Darwin.cosh(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func hyperbolicTangent() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.tanh(self)
|
|
#else
|
|
return Darwin.tanh(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseHyperbolicSine() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.asinh(self)
|
|
#else
|
|
return Darwin.asinh(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseHyperbolicCosine() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.acosh(self)
|
|
#else
|
|
return Darwin.acosh(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseHyperbolicTangent() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.atanh(self)
|
|
#else
|
|
return Darwin.atanh(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public static func hypot(_ x: Double, _ y: Double) -> Double {
|
|
#if os(Linux)
|
|
return Glibc.hypot(x, y)
|
|
#else
|
|
return Darwin.hypot(x, y)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func inverseTangent(dividingBy other: Double) -> Double {
|
|
#if os(Linux)
|
|
return Glibc.atan2(self, other)
|
|
#else
|
|
return Darwin.atan2(self, other)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func error() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.erf(self)
|
|
#else
|
|
return Darwin.erf(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func complementaryError() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.erfc(self)
|
|
#else
|
|
return Darwin.erfc(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func gamma() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.tgamma(self)
|
|
#else
|
|
return Darwin.tgamma(self)
|
|
#endif
|
|
}
|
|
|
|
@_transparent
|
|
public func logarithmicGamma() -> Double {
|
|
#if os(Linux)
|
|
return Glibc.lgamma(self)
|
|
#else
|
|
return Darwin.lgamma(self)
|
|
#endif
|
|
}
|
|
}
|