Skip to content

[stdlib] Add faster 32-bit and 64-bit binade, nextUp, ulp #15021

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 7, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 42 additions & 17 deletions stdlib/public/core/FloatingPointTypes.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,16 @@ extension ${Self}: BinaryFloatingPoint {
/// almost never is.
@_inlineable // FIXME(sil-serialize-all)
public var ulp: ${Self} {
if !isFinite { return ${Self}.nan }
%if bits != 80:
guard _fastPath(isFinite) else { return .nan }
if _fastPath(isNormal) {
let bitPattern_ = bitPattern & ${Self}.infinity.bitPattern
return ${Self}(bitPattern: bitPattern_) * 0x1p-${SignificandBitCount}
}
// On arm, flush subnormal values to 0.
return .leastNormalMagnitude * 0x1p-${SignificandBitCount}
%else:
guard _fastPath(isFinite) else { return .nan }
if exponentBitPattern > UInt(${Self}.significandBitCount) {
// self is large enough that self.ulp is normal, so we just compute its
// exponent and construct it with a significand of zero.
Expand All @@ -645,6 +654,7 @@ extension ${Self}: BinaryFloatingPoint {
return ${Self}(sign: .plus,
exponentBitPattern: 0,
significandBitPattern: 1)
%end
}

/// The least positive normal number.
Expand Down Expand Up @@ -917,17 +927,23 @@ extension ${Self}: BinaryFloatingPoint {
/// - If `x` is `greatestFiniteMagnitude`, then `x.nextUp` is `infinity`.
@_inlineable // FIXME(sil-serialize-all)
public var nextUp: ${Self} {
if isNaN { return self }
if sign == .minus {
%if bits != 80:
// Silence signaling NaNs, map -0 to +0.
let x = self + 0
#if arch(arm)
// On arm, subnormals are flushed to zero.
if (exponentBitPattern == 1 && significandBitPattern == 0) ||
(exponentBitPattern == 0 && significandBitPattern != 0) {
return ${Self}(sign: .minus,
exponentBitPattern: 0,
significandBitPattern: 0)
}
// On arm, treat subnormal values as zero.
if _slowPath(x == 0) { return .leastNonzeroMagnitude }
if _slowPath(x == -.leastNonzeroMagnitude) { return -0.0 }
#endif
if _fastPath(x < .infinity) {
let increment = Int${bits}(bitPattern: x.bitPattern) &>> ${bits - 1} | 1
let bitPattern_ = x.bitPattern &+ UInt${bits}(bitPattern: increment)
return ${Self}(bitPattern: bitPattern_)
}
return x
%else:
if isNaN { /* Silence signaling NaNs. */ return self + 0 }
if sign == .minus {
if significandBitPattern == 0 {
if exponentBitPattern == 0 {
return .leastNonzeroMagnitude
Expand All @@ -946,15 +962,10 @@ extension ${Self}: BinaryFloatingPoint {
exponentBitPattern: exponentBitPattern + 1,
significandBitPattern: 0)
}
#if arch(arm)
// On arm, subnormals are skipped.
if exponentBitPattern == 0 {
return .leastNonzeroMagnitude
}
#endif
return ${Self}(sign: .plus,
exponentBitPattern: exponentBitPattern,
significandBitPattern: significandBitPattern + 1)
%end
}

/// Rounds the value to an integral value using the specified rounding rule.
Expand Down Expand Up @@ -1369,7 +1380,19 @@ extension ${Self}: BinaryFloatingPoint {
/// // y.exponent == 4
@_inlineable // FIXME(sil-serialize-all)
public var binade: ${Self} {
if !isFinite { return .nan }
%if bits != 80:
guard _fastPath(isFinite) else { return .nan }
#if !arch(arm)
if _slowPath(isSubnormal) {
let bitPattern_ =
(self * 0x1p${SignificandBitCount}).bitPattern
& (-${Self}.infinity).bitPattern
return ${Self}(bitPattern: bitPattern_) * 0x1p-${SignificandBitCount}
}
#endif
return ${Self}(bitPattern: bitPattern & (-${Self}.infinity).bitPattern)
%else:
guard _fastPath(isFinite) else { return .nan }
if exponentBitPattern != 0 {
return ${Self}(sign: sign, exponentBitPattern: exponentBitPattern,
significandBitPattern: 0)
Expand All @@ -1379,6 +1402,7 @@ extension ${Self}: BinaryFloatingPoint {
let index = significandBitPattern._binaryLogarithm()
return ${Self}(sign: sign, exponentBitPattern: 0,
significandBitPattern: 1 &<< index)
%end
}

/// The number of bits required to represent the value's significand.
Expand Down Expand Up @@ -1490,6 +1514,7 @@ extension ${Self} : _ExpressibleByBuiltinFloatLiteral {
% if bits == builtinFloatLiteralBits:
self = ${Self}(_bits: value)
% elif bits < builtinFloatLiteralBits:
// FIXME: This can result in double rounding errors (SR-7124).
self = ${Self}(_bits: Builtin.fptrunc_FPIEEE${builtinFloatLiteralBits}_FPIEEE${bits}(value))
% else:
// FIXME: This is actually losing precision <rdar://problem/14073102>.
Expand Down