Skip to content

Commit 73a6aed

Browse files
committed
Add faster 32-bit and 64-bit binade, nextUp, ulp
1 parent e49dbf5 commit 73a6aed

File tree

1 file changed

+52
-16
lines changed

1 file changed

+52
-16
lines changed

stdlib/public/core/FloatingPointTypes.swift.gyb

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,20 @@ 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 == 32 or bits == 64:
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+
#if arch(arm)
635+
// On arm, flush positive subnormal values to 0.
636+
return 0
637+
#else
638+
return .leastNonzeroMagnitude
639+
#endif
640+
%else:
641+
guard _fastPath(isFinite) else { return .nan }
629642
if exponentBitPattern > UInt(${Self}.significandBitCount) {
630643
// self is large enough that self.ulp is normal, so we just compute its
631644
// exponent and construct it with a significand of zero.
@@ -645,6 +658,7 @@ extension ${Self}: BinaryFloatingPoint {
645658
return ${Self}(sign: .plus,
646659
exponentBitPattern: 0,
647660
significandBitPattern: 1)
661+
%end
648662
}
649663

650664
/// The least positive normal number.
@@ -917,17 +931,30 @@ extension ${Self}: BinaryFloatingPoint {
917931
/// - If `x` is `greatestFiniteMagnitude`, then `x.nextUp` is `infinity`.
918932
@_inlineable // FIXME(sil-serialize-all)
919933
public var nextUp: ${Self} {
920-
if isNaN { return self }
921-
if sign == .minus {
934+
%if bits == 32 or bits == 64:
935+
// Silence signaling NaNs, map -0 to +0.
936+
let x = self + 0
922937
#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)
938+
// On arm, skip positive subnormal values.
939+
if _slowPath(x.bitPattern & (-${Self}.infinity).bitPattern == 0) {
940+
return .leastNormalMagnitude
941+
}
942+
#endif
943+
if _fastPath(x < .infinity) {
944+
let increment = Int${bits}(bitPattern: x.bitPattern) &>> ${bits - 1} | 1
945+
let bitPattern_ = x.bitPattern &+ UInt${bits}(bitPattern: increment)
946+
#if arch(arm)
947+
// On arm, flush negative subnormal values to -0.
948+
if _slowPath(bitPattern_ & ${Self}.infinity.bitPattern == 0) {
949+
return -0.0
929950
}
930951
#endif
952+
return ${Self}(bitPattern: bitPattern_)
953+
}
954+
return x
955+
%else:
956+
if isNaN { /* Silence signaling NaNs. */ return self + 0 }
957+
if sign == .minus {
931958
if significandBitPattern == 0 {
932959
if exponentBitPattern == 0 {
933960
return .leastNonzeroMagnitude
@@ -946,15 +973,10 @@ extension ${Self}: BinaryFloatingPoint {
946973
exponentBitPattern: exponentBitPattern + 1,
947974
significandBitPattern: 0)
948975
}
949-
#if arch(arm)
950-
// On arm, subnormals are skipped.
951-
if exponentBitPattern == 0 {
952-
return .leastNonzeroMagnitude
953-
}
954-
#endif
955976
return ${Self}(sign: .plus,
956977
exponentBitPattern: exponentBitPattern,
957978
significandBitPattern: significandBitPattern + 1)
979+
%end
958980
}
959981

960982
/// Rounds the value to an integral value using the specified rounding rule.
@@ -1369,7 +1391,19 @@ extension ${Self}: BinaryFloatingPoint {
13691391
/// // y.exponent == 4
13701392
@_inlineable // FIXME(sil-serialize-all)
13711393
public var binade: ${Self} {
1372-
if !isFinite { return .nan }
1394+
%if bits == 32 or bits == 64:
1395+
guard _fastPath(isFinite) else { return .nan }
1396+
#if !arch(arm)
1397+
if _slowPath(isSubnormal) {
1398+
let bitPattern_ =
1399+
(self * 0x1p${SignificandBitCount}).bitPattern
1400+
& (-${Self}.infinity).bitPattern
1401+
return ${Self}(bitPattern: bitPattern_) / 0x1p${SignificandBitCount}
1402+
}
1403+
#endif
1404+
return ${Self}(bitPattern: bitPattern & (-${Self}.infinity).bitPattern)
1405+
%else:
1406+
guard _fastPath(isFinite) else { return .nan }
13731407
if exponentBitPattern != 0 {
13741408
return ${Self}(sign: sign, exponentBitPattern: exponentBitPattern,
13751409
significandBitPattern: 0)
@@ -1379,6 +1413,7 @@ extension ${Self}: BinaryFloatingPoint {
13791413
let index = significandBitPattern._binaryLogarithm()
13801414
return ${Self}(sign: sign, exponentBitPattern: 0,
13811415
significandBitPattern: 1 &<< index)
1416+
%end
13821417
}
13831418

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

0 commit comments

Comments
 (0)