Skip to content

Commit 94c18c6

Browse files
authored
Merge pull request #15021 from xwu/better-nextups-and-ulps
[stdlib] Add faster 32-bit and 64-bit binade, nextUp, ulp
2 parents 19cf419 + 4c923d6 commit 94c18c6

File tree

1 file changed

+42
-17
lines changed

1 file changed

+42
-17
lines changed

stdlib/public/core/FloatingPointTypes.swift.gyb

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,16 @@ extension ${Self}: BinaryFloatingPoint {
625625
/// almost never is.
626626
@_inlineable // FIXME(sil-serialize-all)
627627
public var ulp: ${Self} {
628-
if !isFinite { return ${Self}.nan }
628+
%if bits != 80:
629+
guard _fastPath(isFinite) else { return .nan }
630+
if _fastPath(isNormal) {
631+
let bitPattern_ = bitPattern & ${Self}.infinity.bitPattern
632+
return ${Self}(bitPattern: bitPattern_) * 0x1p-${SignificandBitCount}
633+
}
634+
// On arm, flush subnormal values to 0.
635+
return .leastNormalMagnitude * 0x1p-${SignificandBitCount}
636+
%else:
637+
guard _fastPath(isFinite) else { return .nan }
629638
if exponentBitPattern > UInt(${Self}.significandBitCount) {
630639
// self is large enough that self.ulp is normal, so we just compute its
631640
// exponent and construct it with a significand of zero.
@@ -645,6 +654,7 @@ extension ${Self}: BinaryFloatingPoint {
645654
return ${Self}(sign: .plus,
646655
exponentBitPattern: 0,
647656
significandBitPattern: 1)
657+
%end
648658
}
649659

650660
/// The least positive normal number.
@@ -917,17 +927,23 @@ extension ${Self}: BinaryFloatingPoint {
917927
/// - If `x` is `greatestFiniteMagnitude`, then `x.nextUp` is `infinity`.
918928
@_inlineable // FIXME(sil-serialize-all)
919929
public var nextUp: ${Self} {
920-
if isNaN { return self }
921-
if sign == .minus {
930+
%if bits != 80:
931+
// Silence signaling NaNs, map -0 to +0.
932+
let x = self + 0
922933
#if arch(arm)
923-
// On arm, subnormals are flushed to zero.
924-
if (exponentBitPattern == 1 && significandBitPattern == 0) ||
925-
(exponentBitPattern == 0 && significandBitPattern != 0) {
926-
return ${Self}(sign: .minus,
927-
exponentBitPattern: 0,
928-
significandBitPattern: 0)
929-
}
934+
// On arm, treat subnormal values as zero.
935+
if _slowPath(x == 0) { return .leastNonzeroMagnitude }
936+
if _slowPath(x == -.leastNonzeroMagnitude) { return -0.0 }
930937
#endif
938+
if _fastPath(x < .infinity) {
939+
let increment = Int${bits}(bitPattern: x.bitPattern) &>> ${bits - 1} | 1
940+
let bitPattern_ = x.bitPattern &+ UInt${bits}(bitPattern: increment)
941+
return ${Self}(bitPattern: bitPattern_)
942+
}
943+
return x
944+
%else:
945+
if isNaN { /* Silence signaling NaNs. */ return self + 0 }
946+
if sign == .minus {
931947
if significandBitPattern == 0 {
932948
if exponentBitPattern == 0 {
933949
return .leastNonzeroMagnitude
@@ -946,15 +962,10 @@ extension ${Self}: BinaryFloatingPoint {
946962
exponentBitPattern: exponentBitPattern + 1,
947963
significandBitPattern: 0)
948964
}
949-
#if arch(arm)
950-
// On arm, subnormals are skipped.
951-
if exponentBitPattern == 0 {
952-
return .leastNonzeroMagnitude
953-
}
954-
#endif
955965
return ${Self}(sign: .plus,
956966
exponentBitPattern: exponentBitPattern,
957967
significandBitPattern: significandBitPattern + 1)
968+
%end
958969
}
959970

960971
/// Rounds the value to an integral value using the specified rounding rule.
@@ -1369,7 +1380,19 @@ extension ${Self}: BinaryFloatingPoint {
13691380
/// // y.exponent == 4
13701381
@_inlineable // FIXME(sil-serialize-all)
13711382
public var binade: ${Self} {
1372-
if !isFinite { return .nan }
1383+
%if bits != 80:
1384+
guard _fastPath(isFinite) else { return .nan }
1385+
#if !arch(arm)
1386+
if _slowPath(isSubnormal) {
1387+
let bitPattern_ =
1388+
(self * 0x1p${SignificandBitCount}).bitPattern
1389+
& (-${Self}.infinity).bitPattern
1390+
return ${Self}(bitPattern: bitPattern_) * 0x1p-${SignificandBitCount}
1391+
}
1392+
#endif
1393+
return ${Self}(bitPattern: bitPattern & (-${Self}.infinity).bitPattern)
1394+
%else:
1395+
guard _fastPath(isFinite) else { return .nan }
13731396
if exponentBitPattern != 0 {
13741397
return ${Self}(sign: sign, exponentBitPattern: exponentBitPattern,
13751398
significandBitPattern: 0)
@@ -1379,6 +1402,7 @@ extension ${Self}: BinaryFloatingPoint {
13791402
let index = significandBitPattern._binaryLogarithm()
13801403
return ${Self}(sign: sign, exponentBitPattern: 0,
13811404
significandBitPattern: 1 &<< index)
1405+
%end
13821406
}
13831407

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

0 commit comments

Comments
 (0)