SE-0246: Protocols and static functions (#23824)

This implements the protocols and static functions proposed in SE-0246, plus some initial test coverage. It also has some rough accompanying cleanup of tgmath. It does not include the globals (on scalars or SIMD types) nor does it deprecate much in tgmath.h.
This commit is contained in:
Stephen Canon
2019-04-17 23:57:33 +02:00
committed by GitHub
parent 1ed77dcf1b
commit 57a4553832
14 changed files with 898 additions and 208 deletions

View File

@@ -509,6 +509,58 @@ public func %=(lhs: inout CGFloat, rhs: CGFloat) {
fatalError("%= is not available.") fatalError("%= is not available.")
} }
//===----------------------------------------------------------------------===//
// Real conformance
//===----------------------------------------------------------------------===//
%from SwiftMathFunctions import *
extension CGFloat: Real {
% for func in ElementaryFunctions + RealFunctions:
@_alwaysEmitIntoClient
public static func ${func.decl('CGFloat')} {
return CGFloat(NativeType.${func.swiftName}(${func.params("", ".native")}))
}
% end
@_alwaysEmitIntoClient
public static func pow(_ x: CGFloat, _ y: CGFloat) -> CGFloat {
guard x >= 0 else { return .nan }
return CGFloat(NativeType.pow(x.native, y.native))
}
@_alwaysEmitIntoClient
public static func pow(_ x: CGFloat, _ n: Int) -> CGFloat {
// TODO: this implementation isn't quite right for n so large that
// the conversion to `CGFloat` 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 CGFloat(NativeType.pow(x.native, n))
}
@_alwaysEmitIntoClient
public static func root(_ x: CGFloat, _ n: Int) -> CGFloat {
guard x >= 0 || n % 2 != 0 else { return .nan }
// TODO: this implementation isn't quite right for n so large that
// the conversion to `CGFloat` rounds.
return CGFloat(NativeType.root(x.native, n))
}
@_alwaysEmitIntoClient
public static func atan2(y: CGFloat, x: CGFloat) -> CGFloat {
return CGFloat(NativeType.atan2(y: y.native, x: x.native))
}
#if !os(Windows)
@_alwaysEmitIntoClient
public static func logGamma(_ x: CGFloat) -> CGFloat {
return CGFloat(NativeType.logGamma(x.native))
}
#endif
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// tgmath // tgmath
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@@ -2,7 +2,7 @@
// //
// This source file is part of the Swift.org open source project // This source file is part of the Swift.org open source project
// //
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception // Licensed under Apache License v2.0 with Runtime Library Exception
// //
// See https://swift.org/LICENSE.txt for license information // See https://swift.org/LICENSE.txt for license information
@@ -14,7 +14,7 @@ import SwiftShims
// Generic functions implementable directly on FloatingPoint. // Generic functions implementable directly on FloatingPoint.
@_transparent @_transparent
@available(swift, deprecated: 4.2, renamed: "abs") @available(swift, deprecated: 4.2, obsoleted: 5.1, renamed: "abs")
public func fabs<T: FloatingPoint>(_ x: T) -> T { public func fabs<T: FloatingPoint>(_ x: T) -> T {
return x.magnitude return x.magnitude
} }
@@ -112,7 +112,7 @@ public func isnan<T: FloatingPoint>(_ value: T) -> Bool { fatalError() }
@available(*, unavailable, message: "use the sign property.") @available(*, unavailable, message: "use the sign property.")
public func signbit<T: FloatingPoint>(_ value: T) -> Int { fatalError() } public func signbit<T: FloatingPoint>(_ value: T) -> Int { fatalError() }
@available(swift, deprecated: 4.2, message: "use the exponent property.") @available(swift, deprecated: 4.2, obsoleted: 5.1, message: "use the exponent property.")
public func ilogb<T: BinaryFloatingPoint>(_ x: T) -> Int { public func ilogb<T: BinaryFloatingPoint>(_ x: T) -> Int {
return Int(x.exponent) return Int(x.exponent)
} }
@@ -155,44 +155,15 @@ UnaryFunctions = [
'acos', 'asin', 'atan', 'tan', 'acos', 'asin', 'atan', 'tan',
'acosh', 'asinh', 'atanh', 'cosh', 'sinh', 'tanh', 'acosh', 'asinh', 'atanh', 'cosh', 'sinh', 'tanh',
'expm1', 'expm1',
'log1p', 'logb', 'log1p',
'cbrt', 'erf', 'erfc', 'tgamma', 'erf', 'erfc',
] ]
# These functions have a corresponding LLVM intrinsic # These functions have a corresponding LLVM intrinsic
# We call this intrinsic via the Builtin method so keep this list in
# sync with core/BuiltinMath.swift.gyb
UnaryIntrinsicFunctions = [ UnaryIntrinsicFunctions = [
'cos', 'sin', 'cos', 'sin', 'exp', 'exp2', 'log', 'log10', 'log2', 'nearbyint', 'rint'
'exp', 'exp2',
'log', 'log10', 'log2',
'nearbyint', 'rint',
] ]
# (T, T) -> T
BinaryFunctions = [
'atan2', 'hypot', 'pow',
'copysign', 'nextafter', 'fdim', 'fmax', 'fmin'
]
# These functions have special implementations.
OtherFunctions = [
'scalbn', 'lgamma', 'remquo', 'nan', 'jn', 'yn'
]
# These functions are imported correctly as-is.
OkayFunctions = ['j0', 'j1', 'y0', 'y1']
# These functions are not supported for various reasons.
UnhandledFunctions = [
'math_errhandling', 'scalbln',
'lrint', 'lround', 'llrint', 'llround', 'nexttoward',
'isgreater', 'isgreaterequal', 'isless', 'islessequal',
'islessgreater', 'isunordered', '__exp10',
'__sincos', '__cospi', '__sinpi', '__tanpi', '__sincospi'
]
def AllFloatTypes(): def AllFloatTypes():
for bits in allFloatBits: for bits in allFloatBits:
yield floatName(bits), cFloatName(bits), cFuncSuffix(bits) yield floatName(bits), cFloatName(bits), cFuncSuffix(bits)
@@ -226,60 +197,117 @@ def TypedBinaryFunctions():
% end % end
@_transparent @_transparent
public func ${ufunc}(_ x: ${T}) -> ${T} { public func ${ufunc}(_ x: ${T}) -> ${T} {
return ${T}(${ufunc}${f}(${CT}(x))) return ${T}.${ufunc}(x)
} }
% if T == 'Float80': % if T == 'Float80':
#endif #endif
% end % end
% end % end
@_transparent
public func cbrt(_ x: Float) -> Float {
return Float.root(x, 3)
}
@available(swift, deprecated: 5.1, message: "Use `x.exponent` or `floor(log2(x))`.")
@_transparent
public func logb(_ x: Float) -> Float {
return Float.log2(x).rounded(.down)
}
@_transparent
public func tgamma(_ x: Float) -> Float {
return Float.gamma(x)
}
#if (arch(i386) || arch(x86_64)) && !os(Windows)
@_transparent
public func cbrt(_ x: Float80) -> Float80 {
return Float80.root(x, 3)
}
@available(swift, deprecated: 5.1, message: "Use `x.exponent` or `floor(log2(x))`.")
@_transparent
public func logb(_ x: Float80) -> Float80 {
return Float80.log2(x).rounded(.down)
}
@_transparent
public func tgamma(_ x: Float80) -> Float80 {
return Float80.gamma(x)
}
#endif
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
// Unary intrinsic functions // Unary intrinsic functions
// Note these have a corresponding LLVM intrinsic // Note these have a corresponding LLVM intrinsic
% for T, ufunc in TypedUnaryIntrinsicFunctions(): % for T, ufunc in TypedUnaryIntrinsicFunctions():
% if T == 'Float80': % if T == 'Float80':
#if (arch(i386) || arch(x86_64)) && !os(Windows) #if (arch(i386) || arch(x86_64)) && !os(Windows)
% end % end
% if ufunc[-3:] != 'int':
@_transparent @_transparent
public func ${ufunc}(_ x: ${T}) -> ${T} { public func ${ufunc}(_ x: ${T}) -> ${T} {
return _${ufunc}(x) return ${T}.${ufunc}(x)
} }
% else:
@available(swift, deprecated: 5.1, message: "Swift does not model dynamic rounding modes, use x.rounded(.toNearestOrEven) instead.")
@_transparent
public func ${ufunc}(_ x: ${T}) -> ${T} {
return x.rounded(.toNearestOrEven)
}
% end
% if T == 'Float80': % if T == 'Float80':
#endif #endif
% end % end
% end % end
#else
// FIXME: As of now, we cannot declare 64-bit (Double/CDouble) overlays here.
// Since CoreFoundation also exports libc functions, they will conflict with
// Swift overlays when building Foundation. For now, just like normal
// UnaryFunctions, we define overlays only for OverlayFloatTypes.
% for ufunc in UnaryIntrinsicFunctions:
% for T, CT, f in OverlayFloatTypes():
% if T == 'Float80':
#if (arch(i386) || arch(x86_64)) && !os(Windows)
% end
@_transparent
public func ${ufunc}(_ x: ${T}) -> ${T} {
return ${T}(${ufunc}${f}(${CT}(x)))
}
% if T == 'Float80':
#endif
% end
% end
% end
#endif
// Binary functions // Binary functions
% for T, CT, f in OverlayFloatTypes():
% for T, CT, f, bfunc in TypedBinaryFunctions():
% if T == 'Float80': % if T == 'Float80':
#if (arch(i386) || arch(x86_64)) && !os(Windows) #if (arch(i386) || arch(x86_64)) && !os(Windows)
% end % end
@_transparent @_transparent
public func ${bfunc}(_ lhs: ${T}, _ rhs: ${T}) -> ${T} { public func atan2(_ y: ${T}, _ x: ${T}) -> ${T} {
return ${T}(${bfunc}${f}(${CT}(lhs), ${CT}(rhs))) return ${T}.atan2(y: y, x: x)
}
@_transparent
public func hypot(_ x: ${T}, _ y: ${T}) -> ${T} {
return ${T}.hypot(x, y)
}
@_transparent
public func pow(_ x: ${T}, _ y: ${T}) -> ${T} {
return ${T}.pow(x, y)
}
@_transparent
public func copysign(_ x: ${T}, _ y: ${T}) -> ${T} {
return ${T}(signOf: y, magnitudeOf: x)
}
@_transparent
public func fdim(_ x: ${T}, _ y: ${T}) -> ${T} {
return ${T}(fdim${f}(${CT}(x), ${CT}(y)))
}
@available(swift, deprecated: 5.1, message: "Use the .nextUp and .nextDown properties.")
@_transparent
public func nextafter(_ x: ${T}, _ y: ${T}) -> ${T} {
return y > x ? x.nextUp : (y < x ? x.nextDown : y)
}
@available(swift, deprecated: 5.1, message: "Use ${T}.minimum( ) or Swift.min( )")
@_transparent
public func fmin(_ x: ${T}, _ y: ${T}) -> ${T} {
return .minimum(x, y)
}
@available(swift, deprecated: 5.1, message: "Use ${T}.maximum( ) or Swift.max( )")
@_transparent
public func fmax(_ x: ${T}, _ y: ${T}) -> ${T} {
return .maximum(x, y)
} }
% if T == 'Float80': % if T == 'Float80':
#endif #endif
@@ -297,9 +325,7 @@ public func ${bfunc}(_ lhs: ${T}, _ rhs: ${T}) -> ${T} {
% end % end
@_transparent @_transparent
public func lgamma(_ x: ${T}) -> (${T}, Int) { public func lgamma(_ x: ${T}) -> (${T}, Int) {
var sign = Int32(0) return (${T}.logGamma(x), ${T}.signGamma(x) == .plus ? 1 : -1)
let value = lgamma${f}_r(${CT}(x), &sign)
return (${T}(value), Int(sign))
} }
#endif #endif
@@ -326,8 +352,8 @@ public func remquo(_ x: ${T}, _ y: ${T}) -> (${T}, Int) {
% if T == 'Float80': % if T == 'Float80':
#if (arch(i386) || arch(x86_64)) && !os(Windows) #if (arch(i386) || arch(x86_64)) && !os(Windows)
% end % end
@available(swift, deprecated: 4.2, message: @available(swift, deprecated: 4.2, obsoleted: 5.1, message:
"use ${T}(nan: ${T}.RawSignificand) instead.") "use ${T}(nan: ${T}.RawSignificand).")
@_transparent @_transparent
public func nan(_ tag: String) -> ${T} { public func nan(_ tag: String) -> ${T} {
return ${T}(nan${f}(tag)) return ${T}(nan${f}(tag))

View File

@@ -127,46 +127,343 @@ static inline __swift_size_t _swift_stdlib_malloc_size(const void *ptr) {
// Math library functions // Math library functions
static inline SWIFT_ALWAYS_INLINE static inline SWIFT_ALWAYS_INLINE
float _stdlib_remainderf(float _self, float _other) { float _swift_stdlib_remainderf(float _self, float other) {
return __builtin_remainderf(_self, _other); return __builtin_remainderf(_self, other);
} }
static inline SWIFT_ALWAYS_INLINE static inline SWIFT_ALWAYS_INLINE
float _stdlib_squareRootf(float _self) { float _swift_stdlib_squareRootf(float _self) {
return __builtin_sqrtf(_self); return __builtin_sqrtf(_self);
} }
static inline SWIFT_ALWAYS_INLINE static inline SWIFT_ALWAYS_INLINE
double _stdlib_remainder(double _self, double _other) { float _swift_stdlib_tanf(float x) {
return __builtin_remainder(_self, _other); return __builtin_tanf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_acosf(float x) {
return __builtin_acosf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_asinf(float x) {
return __builtin_asinf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_atanf(float x) {
return __builtin_atanf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_atan2f(float y, float x) {
return __builtin_atan2f(y, x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_coshf(float x) {
return __builtin_coshf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_sinhf(float x) {
return __builtin_sinhf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_tanhf(float x) {
return __builtin_tanhf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_acoshf(float x) {
return __builtin_acoshf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_asinhf(float x) {
return __builtin_asinhf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_atanhf(float x) {
return __builtin_atanhf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_exp10f(float x) {
#if defined __APPLE__
extern float __exp10f(float);
return __exp10f(x);
#else
return __builtin_powf(10, x);
#endif
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_expm1f(float x) {
return __builtin_expm1f(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_log1pf(float x) {
return __builtin_log1pf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_hypotf(float x, float y) {
#if defined(_WIN32)
extern float _hypotf(float, float);
return _hypotf(x, y);
#else
return __builtin_hypotf(x, y);
#endif
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_erff(float x) {
return __builtin_erff(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_erfcf(float x) {
return __builtin_erfcf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_tgammaf(float x) {
return __builtin_tgammaf(x);
}
static inline SWIFT_ALWAYS_INLINE
float _swift_stdlib_lgammaf(float x) {
extern float lgammaf_r(float x, int *psigngam);
int dontCare;
return lgammaf_r(x, &dontCare);
} }
static inline SWIFT_ALWAYS_INLINE static inline SWIFT_ALWAYS_INLINE
double _stdlib_squareRoot(double _self) { double _swift_stdlib_remainder(double _self, double other) {
return __builtin_remainder(_self, other);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_squareRoot(double _self) {
return __builtin_sqrt(_self); return __builtin_sqrt(_self);
} }
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_tan(double x) {
return __builtin_tan(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_acos(double x) {
return __builtin_acos(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_asin(double x) {
return __builtin_asin(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_atan(double x) {
return __builtin_atan(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_atan2(double y, double x) {
return __builtin_atan2(y, x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_cosh(double x) {
return __builtin_cosh(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_sinh(double x) {
return __builtin_sinh(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_tanh(double x) {
return __builtin_tanh(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_acosh(double x) {
return __builtin_acosh(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_asinh(double x) {
return __builtin_asinh(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_atanh(double x) {
return __builtin_atanh(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_exp10(double x) {
#if defined __APPLE__
extern double __exp10(double);
return __exp10(x);
#else
return __builtin_pow(10, x);
#endif
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_expm1(double x) {
return __builtin_expm1(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_log1p(double x) {
return __builtin_log1p(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_hypot(double x, double y) {
return __builtin_hypot(x, y);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_erf(double x) {
return __builtin_erf(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_erfc(double x) {
return __builtin_erfc(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_tgamma(double x) {
return __builtin_tgamma(x);
}
static inline SWIFT_ALWAYS_INLINE
double _swift_stdlib_lgamma(double x) {
extern double lgamma_r(double x, int *psigngam);
int dontCare;
return lgamma_r(x, &dontCare);
}
#if !defined _WIN32 && (defined __i386__ || defined __x86_64__) #if !defined _WIN32 && (defined __i386__ || defined __x86_64__)
static inline SWIFT_ALWAYS_INLINE static inline SWIFT_ALWAYS_INLINE
long double _stdlib_remainderl(long double _self, long double _other) { long double _swift_stdlib_remainderl(long double _self, long double other) {
return __builtin_remainderl(_self, _other); return __builtin_remainderl(_self, other);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_squareRootl(long double _self) {
return __builtin_sqrtl(_self);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_tanl(long double x) {
return __builtin_tanl(x);
} }
static inline SWIFT_ALWAYS_INLINE static inline SWIFT_ALWAYS_INLINE
long double _stdlib_squareRootl(long double _self) { long double _swift_stdlib_acosl(long double x) {
return __builtin_sqrtl(_self); return __builtin_acosl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_asinl(long double x) {
return __builtin_asinl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_atanl(long double x) {
return __builtin_atanl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_atan2l(long double y, long double x) {
return __builtin_atan2l(y, x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_coshl(long double x) {
return __builtin_coshl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_sinhl(long double x) {
return __builtin_sinhl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_tanhl(long double x) {
return __builtin_tanhl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_acoshl(long double x) {
return __builtin_acoshl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_asinhl(long double x) {
return __builtin_asinhl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_atanhl(long double x) {
return __builtin_atanhl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_exp10l(long double x) {
return __builtin_powl(10, x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_expm1l(long double x) {
return __builtin_expm1l(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_log1pl(long double x) {
return __builtin_log1pl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_hypotl(long double x, long double y) {
return __builtin_hypotl(x, y);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_erfl(long double x) {
return __builtin_erfl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_erfcl(long double x) {
return __builtin_erfcl(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_tgammal(long double x) {
return __builtin_tgammal(x);
}
static inline SWIFT_ALWAYS_INLINE
long double _swift_stdlib_lgammal(long double x) {
extern long double lgammal_r(long double x, int *psigngam);
int dontCare;
return lgammal_r(x, &dontCare);
} }
#endif #endif
// Apple's math.h does not declare lgamma_r() etc by default, but they're
// unconditionally exported by libsystem_m.dylib in all OS versions that
// support Swift development; we simply need to provide declarations here.
#if defined(__APPLE__)
float lgammaf_r(float x, int *psigngam);
double lgamma_r(double x, int *psigngam);
long double lgammal_r(long double x, int *psigngam);
#endif // defined(__APPLE__)
#ifdef __cplusplus #ifdef __cplusplus
}} // extern "C", namespace swift }} // extern "C", namespace swift
#endif #endif

View File

@@ -1,78 +0,0 @@
//===--- BuiltinMath.swift.gyb --------------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
%{
# Don't need 64-bit (Double/CDouble) overlays. The ordinary C imports work fine.
overlayFloatBits = [32, 80]
allFloatBits = [32, 64, 80]
def floatName(bits):
if bits == 32:
return 'Float'
if bits == 64:
return 'Double'
if bits == 80:
return 'Float80'
def cFloatName(bits):
if bits == 32:
return 'CFloat'
if bits == 64:
return 'CDouble'
if bits == 80:
return 'CLongDouble'
def cFuncSuffix(bits):
if bits == 32:
return 'f'
if bits == 64:
return ''
if bits == 80:
return 'l'
# Each of the following lists is ordered to match math.h
# These functions have a corresponding LLVM intrinsic
# Note, keep this up to date with Darwin/tgmath.swift.gyb
UnaryIntrinsicFunctions = [
'cos', 'sin',
'exp', 'exp2',
'log', 'log10', 'log2',
'nearbyint', 'rint',
]
def TypedUnaryIntrinsicFunctions():
for ufunc in UnaryIntrinsicFunctions:
for bits in allFloatBits:
yield floatName(bits), cFloatName(bits), bits, ufunc
}%
// Unary intrinsic functions
// Note these have a corresponding LLVM intrinsic
% for T, CT, bits, ufunc in TypedUnaryIntrinsicFunctions():
% if bits == 80:
#if !os(Windows) && (arch(i386) || arch(x86_64))
% end
@_transparent
public func _${ufunc}(_ x: ${T}) -> ${T} {
return ${T}(Builtin.int_${ufunc}_FPIEEE${bits}(x._value))
}
% if bits == 80:
#endif
% end
% end
// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End:

View File

@@ -184,7 +184,6 @@ set(SWIFTLIB_ESSENTIAL
set(SWIFTLIB_ESSENTIAL_GYB_SOURCES set(SWIFTLIB_ESSENTIAL_GYB_SOURCES
AtomicInt.swift.gyb AtomicInt.swift.gyb
BuiltinMath.swift.gyb
Codable.swift.gyb Codable.swift.gyb
FixedArray.swift.gyb FixedArray.swift.gyb
FloatingPointParsing.swift.gyb FloatingPointParsing.swift.gyb
@@ -218,10 +217,11 @@ set(SWIFTLIB_SOURCES
) )
set(SWIFTLIB_GYB_SOURCES set(SWIFTLIB_GYB_SOURCES
${SWIFTLIB_ESSENTIAL_GYB_SOURCES} ${SWIFTLIB_ESSENTIAL_GYB_SOURCES}
ExistentialCollection.swift.gyb ExistentialCollection.swift.gyb
SIMDVectorTypes.swift.gyb MathFunctions.swift.gyb
Tuple.swift.gyb SIMDVectorTypes.swift.gyb
Tuple.swift.gyb
) )
set(GROUP_INFO_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/GroupInfo.json) set(GROUP_INFO_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/GroupInfo.json)
set(swift_core_link_flags "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}") set(swift_core_link_flags "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}")

View File

@@ -1898,10 +1898,6 @@ extension FloatingPoint {
/// other is NaN. /// other is NaN.
@inlinable @inlinable
public static func minimum(_ x: Self, _ y: Self) -> Self { public static func minimum(_ x: Self, _ y: Self) -> Self {
if x.isSignalingNaN || y.isSignalingNaN {
// Produce a quiet NaN matching platform arithmetic behavior.
return x + y
}
if x <= y || y.isNaN { return x } if x <= y || y.isNaN { return x }
return y return y
} }
@@ -1935,10 +1931,6 @@ extension FloatingPoint {
/// other is NaN. /// other is NaN.
@inlinable @inlinable
public static func maximum(_ x: Self, _ y: Self) -> Self { public static func maximum(_ x: Self, _ y: Self) -> Self {
if x.isSignalingNaN || y.isSignalingNaN {
// Produce a quiet NaN matching platform arithmetic behavior.
return x + y
}
if x > y || y.isNaN { return x } if x > y || y.isNaN { return x }
return y return y
} }
@@ -1974,10 +1966,6 @@ extension FloatingPoint {
/// a number if the other is NaN. /// a number if the other is NaN.
@inlinable @inlinable
public static func minimumMagnitude(_ x: Self, _ y: Self) -> Self { public static func minimumMagnitude(_ x: Self, _ y: Self) -> Self {
if x.isSignalingNaN || y.isSignalingNaN {
// Produce a quiet NaN matching platform arithmetic behavior.
return x + y
}
if x.magnitude <= y.magnitude || y.isNaN { return x } if x.magnitude <= y.magnitude || y.isNaN { return x }
return y return y
} }
@@ -2013,10 +2001,6 @@ extension FloatingPoint {
/// a number if the other is NaN. /// a number if the other is NaN.
@inlinable @inlinable
public static func maximumMagnitude(_ x: Self, _ y: Self) -> Self { public static func maximumMagnitude(_ x: Self, _ y: Self) -> Self {
if x.isSignalingNaN || y.isSignalingNaN {
// Produce a quiet NaN matching platform arithmetic behavior.
return x + y
}
if x.magnitude > y.magnitude || y.isNaN { return x } if x.magnitude > y.magnitude || y.isNaN { return x }
return y return y
} }

View File

@@ -1115,7 +1115,7 @@ extension ${Self}: BinaryFloatingPoint {
@inlinable // FIXME(inline-always) @inlinable // FIXME(inline-always)
@inline(__always) @inline(__always)
public mutating func formRemainder(dividingBy other: ${Self}) { public mutating func formRemainder(dividingBy other: ${Self}) {
self = _stdlib_remainder${cFuncSuffix}(self, other) self = _swift_stdlib_remainder${cFuncSuffix}(self, other)
} }
/// Replaces this value with the remainder of itself divided by the given /// Replaces this value with the remainder of itself divided by the given
@@ -1157,7 +1157,7 @@ extension ${Self}: BinaryFloatingPoint {
/// value. /// value.
@_transparent @_transparent
public mutating func formSquareRoot( ) { public mutating func formSquareRoot( ) {
self = _stdlib_squareRoot${cFuncSuffix}(self) self = _swift_stdlib_squareRoot${cFuncSuffix}(self)
} }
/// Adds the product of the two given values to this value in place, computed /// Adds the product of the two given values to this value in place, computed

View File

@@ -158,7 +158,7 @@
], ],
"Math": [ "Math": [
"SetAlgebra.swift", "SetAlgebra.swift",
"BuiltinMath.swift", "MathFunctions.swift",
{ {
"Integers": [ "Integers": [
"Integers.swift", "Integers.swift",

View File

@@ -0,0 +1,180 @@
//===--- 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

View File

@@ -13,13 +13,7 @@
// Make sure we use an intrinsic for functions such as exp. // Make sure we use an intrinsic for functions such as exp.
// CHECK-LABEL: define {{.*}}test1 // CHECK-LABEL: define {{.*}}test1
// CHECK-ios: call float @llvm.exp.f32 // CHECK: call float @llvm.exp.f32
// CHECK-macosx: call float @llvm.exp.f32
// CHECK-tvos: call float @llvm.exp.f32
// CHECK-watchos: call float @llvm.exp.f32
// CHECK-darwin: call float @llvm.exp.f32
// CHECK-linux-gnu: call float @expf
// CHECK-windows: call float @expf
public func test1(f : Float) -> Float { public func test1(f : Float) -> Float {
return exp(f) return exp(f)
@@ -29,7 +23,7 @@ public func test1(f : Float) -> Float {
// CHECK: call double @llvm.exp.f64 // CHECK: call double @llvm.exp.f64
public func test2(f : Double) -> Double { public func test2(f : Double) -> Double {
return _exp(f) return .exp(f)
} }
// CHECK-LABEL: define {{.*}}test3 // CHECK-LABEL: define {{.*}}test3

View File

@@ -1 +1,9 @@
Func _cos(_:) has been removed
Func _exp(_:) has been removed
Func _exp2(_:) has been removed
Func _log(_:) has been removed
Func _log10(_:) has been removed
Func _log2(_:) has been removed
Func _nearbyint(_:) has been removed
Func _rint(_:) has been removed
Func _sin(_:) has been removed

View File

@@ -0,0 +1,114 @@
//===--- Math.swift.gyb ---------------------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 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
//
//===----------------------------------------------------------------------===//
// -*- swift -*-
// RUN: %empty-directory(%t)
// RUN: %gyb %s -o %t/tgmath.swift
// RUN: %line-directive %t/tgmath.swift -- %target-build-swift %t/tgmath.swift -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %line-directive %t/tgmath.swift -- %target-run %t/a.out
// REQUIRES: executable_test
#if (arch(i386) || arch(x86_64)) && !os(Windows)
typealias TestLiteralType = Float80
#else
typealias TestLiteralType = Double
#endif
import StdlibUnittest
let MathTests = TestSuite("Math")
func expectEqualWithTolerance<T>(_ expected: TestLiteralType, _ actual: T,
ulps allowed: T = 3,
file: String = #file, line: UInt = #line)
where T: BinaryFloatingPoint {
if actual == T(expected) || actual.isNaN && expected.isNaN {
return
}
// Compute error in ulp, compare to tolerance.
let absoluteError = T(abs(TestLiteralType(actual) - expected))
let ulpError = absoluteError / T(expected).ulp
expectTrue(ulpError <= allowed,
"\(actual) != \(expected) as \(T.self)" +
"\n \(ulpError)-ulp error exceeds \(allowed)-ulp tolerance.",
file: file, line: line)
}
%from SwiftMathFunctions import *
internal extension ElementaryFunctions where Self: BinaryFloatingPoint {
static func elementaryFunctionTests() {
/* Default tolerance is 3 ulps unless specified otherwise. It's OK to relax
* this as needed for new platforms, as these tests are *not* intended to
* validate the math library--they are only intended to check that the
* Swift bindings are calling the right functions in the math library. */
expectEqualWithTolerance(1.1863995522992575361931268186727044683, Self.acos(0.375))
expectEqualWithTolerance(0.3843967744956390830381948729670469737, Self.asin(0.375))
expectEqualWithTolerance(0.3587706702705722203959200639264604997, Self.atan(0.375))
expectEqualWithTolerance(0.9305076219123142911494767922295555080, Self.cos(0.375))
expectEqualWithTolerance(0.3662725290860475613729093517162641571, Self.sin(0.375))
expectEqualWithTolerance(0.3936265759256327582294137871012180981, Self.tan(0.375))
expectEqualWithTolerance(0.4949329230945269058895630995767185785, Self.acosh(1.125))
expectEqualWithTolerance(0.9670596312833237113713762009167286709, Self.asinh(1.125))
expectEqualWithTolerance(0.7331685343967135223291211023213964500, Self.atanh(0.625))
expectEqualWithTolerance(1.0711403467045867672994980155670160493, Self.cosh(0.375))
expectEqualWithTolerance(0.3838510679136145687542956764205024589, Self.sinh(0.375))
expectEqualWithTolerance(0.3583573983507859463193602315531580424, Self.tanh(0.375))
expectEqualWithTolerance(1.4549914146182013360537936919875185083, Self.exp(0.375))
expectEqualWithTolerance(1.2968395546510096659337541177924511598, Self.exp2(0.375))
expectEqualWithTolerance(2.3713737056616552616517527574788898386, Self.exp10(0.375))
expectEqualWithTolerance(0.4549914146182013360537936919875185083, Self.expm1(0.375))
expectEqualWithTolerance(-0.980829253011726236856451127452003999, Self.log(0.375))
expectEqualWithTolerance(-1.415037499278843818546261056052183491, Self.log2(0.375))
expectEqualWithTolerance(0.3184537311185346158102472135905995955, Self.log1p(0.375))
expectEqualWithTolerance(-0.425968732272281148346188780918363771, Self.log10(0.375))
expectEqualWithTolerance(0.7211247851537041911608191553900547941, Self.root(0.375, 3))
expectEqualWithTolerance(0.6123724356957945245493210186764728479, Self.sqrt(0.375))
expectEqualWithTolerance(0.54171335479545025876069682133938570, Self.pow(0.375, 0.625))
expectEqualWithTolerance(-0.052734375, Self.pow(-0.375, 3))
}
}
internal extension Real where Self: BinaryFloatingPoint {
static func realFunctionTests() {
expectEqualWithTolerance(0.54041950027058415544357836460859991, Self.atan2(y: 0.375, x: 0.625))
expectEqualWithTolerance(0.72886898685566255885926910969319788, Self.hypot(0.375, 0.625))
expectEqualWithTolerance(0.4041169094348222983238250859191217675, Self.erf(0.375))
expectEqualWithTolerance(0.5958830905651777016761749140808782324, Self.erfc(0.375))
expectEqualWithTolerance(2.3704361844166009086464735041766525098, Self.gamma(0.375))
#if !os(Windows)
expectEqualWithTolerance( -0.11775527074107877445136203331798850, Self.logGamma(1.375), ulps: 16)
expectEqual(.plus, Self.signGamma(1.375))
expectEqual(.minus, Self.signGamma(-2.375))
#endif
}
}
%for T in ['Float', 'Double', 'CGFloat', 'Float80']:
% if T == 'Float80':
#if (arch(i386) || arch(x86_64)) && !os(Windows)
% elif T == 'CGFloat':
#if canImport(CoreGraphics)
import CoreGraphics
% end
MathTests.test("${T}") {
${T}.elementaryFunctionTests()
${T}.realFunctionTests()
}
% if T in ['CGFloat', 'Float80']:
#endif
% end
%end
runAllTests()

View File

@@ -181,21 +181,49 @@ internal extension TGMath {
% end % end
extension ${T}: TGMath { extension ${T}: TGMath {
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
% Module = 'CoreGraphics' if T == 'CGFloat' else 'Darwin'
% for f in unary: % for f in unary:
static func _${f}(_ x: ${T}) -> ${T} { return ${f}(x) } static func _${f}(_ x: ${T}) -> ${T} { return ${Module}.${f}(x) }
% end % end
%for f in binary: %for f in binary:
static func _${f}(_ x: ${T}, _ y: ${T}) -> ${T} { return ${f}(x, y) } static func _${f}(_ x: ${T}, _ y: ${T}) -> ${T} { return ${Module}.${f}(x, y) }
%end %end
static func _remquo(_ x: ${T}, _ y: ${T}) -> (${T}, Int) { return remquo(x, y) } static func _remquo(_ x: ${T}, _ y: ${T}) -> (${T}, Int) { return ${Module}.remquo(x, y) }
static func _fma(_ x: ${T}, _ y: ${T}, _ z: ${T}) -> ${T} { return fma(x, y, z) } static func _fma(_ x: ${T}, _ y: ${T}, _ z: ${T}) -> ${T} { return ${Module}.fma(x, y, z) }
#if !os(Windows) static func _lgamma(_ x: ${T}) -> (${T}, Int) { return ${Module}.lgamma(x) }
static func _lgamma(_ x: ${T}) -> (${T}, Int) { return lgamma(x) } static func _modf(_ x: ${T}) -> (${T}, ${T}) { return ${Module}.modf(x) }
static func _scalbn(_ x: ${T}, _ n: Int) -> ${T} { return ${Module}.scalbn(x, n) }
static func _frexp(_ x: ${T}) -> (${T}, Int) { return ${Module}.frexp(x) }
static func _ilogb(_ x: ${T}) -> Int { return ${Module}.ilogb(x) }
#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku)
% for f in unary:
static func _${f}(_ x: ${T}) -> ${T} { return Glibc.${f}(x) }
% end
%for f in binary:
static func _${f}(_ x: ${T}, _ y: ${T}) -> ${T} { return Glibc.${f}(x, y) }
%end
static func _remquo(_ x: ${T}, _ y: ${T}) -> (${T}, Int) { return Glibc.remquo(x, y) }
static func _fma(_ x: ${T}, _ y: ${T}, _ z: ${T}) -> ${T} { return Glibc.fma(x, y, z) }
static func _lgamma(_ x: ${T}) -> (${T}, Int) { return Glibc.lgamma(x) }
static func _modf(_ x: ${T}) -> (${T}, ${T}) { return Glibc.modf(x) }
static func _scalbn(_ x: ${T}, _ n: Int) -> ${T} { return Glibc.scalbn(x, n) }
static func _frexp(_ x: ${T}) -> (${T}, Int) { return Glibc.frexp(x) }
static func _ilogb(_ x: ${T}) -> Int { return Glibc.ilogb(x) }
#elseif os(Windows)
% for f in unary:
static func _${f}(_ x: ${T}) -> ${T} { return MSVCRT.${f}(x) }
% end
%for f in binary:
static func _${f}(_ x: ${T}, _ y: ${T}) -> ${T} { return MSVCRT.${f}(x, y) }
%end
static func _remquo(_ x: ${T}, _ y: ${T}) -> (${T}, Int) { return MSVCRT.remquo(x, y) }
static func _fma(_ x: ${T}, _ y: ${T}, _ z: ${T}) -> ${T} { return MSVCRT.fma(x, y, z) }
static func _modf(_ x: ${T}) -> (${T}, ${T}) { return MSVCRT.modf(x) }
static func _scalbn(_ x: ${T}, _ n: Int) -> ${T} { return MSVCRT.scalbn(x, n) }
static func _frexp(_ x: ${T}) -> (${T}, Int) { return MSVCRT.frexp(x) }
static func _ilogb(_ x: ${T}) -> Int { return MSVCRT.ilogb(x) }
#endif #endif
static func _modf(_ x: ${T}) -> (${T}, ${T}) { return modf(x) }
static func _scalbn(_ x: ${T}, _ n: Int) -> ${T} { return scalbn(x, n) }
static func _frexp(_ x: ${T}) -> (${T}, Int) { return frexp(x) }
static func _ilogb(_ x: ${T}) -> Int { return ilogb(x) }
} }
MathTests.test("${T}") { MathTests.test("${T}") {

View File

@@ -0,0 +1,85 @@
class SwiftMathFunction(object):
def __init__(self, name, kind=None, swiftName=None, args="x", comment=None,
platforms=None):
self.name = name
self.swiftName = swiftName if swiftName is not None else name
self.kind = kind if kind is not None else "library"
self.args = args
if comment is not None:
self.comment = comment
else:
self.comment = "/// The " + str(self.swiftName) + " function."
self.platforms = platforms
def params(self, prefix="", suffix=""):
return ", ".join(map(lambda a: prefix + a + suffix, self.args))
def decl(self, type):
return self.swiftName + "(" + self.params("_ ", ": " + type) + \
") -> " + type
def free_decl(self, constraint="T: ElementaryFunctions"):
return self.swiftName + "<T>(" + self.params("_ ", ": T") + \
") -> T where " + constraint
def impl(self, type):
if self.kind == "intrinsic":
builtin = "Builtin.int_" + self.name + "_FPIEEE" + str(type.bits)
return type.stdlib_name + "(" + builtin + "(" + \
self.params("", "._value") + "))"
return "_swift_stdlib_" + self.name + type.cFuncSuffix + "(" + \
self.params() + ")"
ElementaryFunctions = [
SwiftMathFunction(name="sqrt", kind="intrinsic", comment="""
/// The square root of `x`.
///
/// For real types, if the argument is negative, either the result is NaN
/// or a precondition failure occurs. For complex types, this function has
/// a branch cut along the negative real axis.
"""),
SwiftMathFunction(name="cos", kind="intrinsic", comment="""
/// The cosine of `x`.
///
/// For real types, `x` is interpreted as an angle measured in radians.
"""),
SwiftMathFunction(name="sin", kind="intrinsic", comment="""
/// The sine of `x`.
///
/// For real types, `x` is interpreted as an angle measured in radians.
"""),
SwiftMathFunction(name="tan",
comment="/// The tangent of `x`."),
SwiftMathFunction(name="acos"),
SwiftMathFunction(name="asin"),
SwiftMathFunction(name="atan"),
SwiftMathFunction(name="cosh"),
SwiftMathFunction(name="sinh"),
SwiftMathFunction(name="tanh"),
SwiftMathFunction(name="acosh"),
SwiftMathFunction(name="asinh"),
SwiftMathFunction(name="atanh"),
SwiftMathFunction(name="exp", kind="intrinsic"),
SwiftMathFunction(name="exp2", kind="intrinsic"),
SwiftMathFunction(name="exp10"),
SwiftMathFunction(name="expm1"),
SwiftMathFunction(name="log", kind="intrinsic"),
SwiftMathFunction(name="log2", kind="intrinsic"),
SwiftMathFunction(name="log10", kind="intrinsic"),
SwiftMathFunction(name="log1p"),
# SwiftMathFunction(name="pow", kind="intrinsic", args="xy"), Handled
# separately for edge cases.
# SwiftMathFunction(name="root", args="xn"), Handled separately for
# implementation.
]
RealFunctions = [
# SwiftMathFunction(name="atan2"), Handled separately for explicit
# argument labels.
SwiftMathFunction(name="erf"),
SwiftMathFunction(name="erfc"),
SwiftMathFunction(name="hypot", args="xy"),
SwiftMathFunction(name="tgamma", swiftName="gamma"),
# SwiftMathFunction(name="lgamma"), Handled separately for sign result.
]