Skip to content

Commit 9c08fbf

Browse files
SE-0113 + residual SE-0067 work (#3443)
Implemented SE-0113 + residual SE-0067 operations. - adds `rounded` and `round` to `FloatingPoint`, from SE-0113. - adds `remainder`, `squareRoot`, and `addingProduct`, from SE-0067. - adds basic test coverage for all of the above. - provides a default implementation of `nextDown` on `FloatingPoint`.
1 parent e2501ad commit 9c08fbf

File tree

6 files changed

+395
-31
lines changed

6 files changed

+395
-31
lines changed

stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,12 @@ public struct CGFloat {
166166
exponent: exponent, significand: significand.native)
167167
}
168168

169-
public var nextUp: CGFloat {
170-
return CGFloat(native.nextUp)
169+
public mutating func round(_ rule: FloatingPointRoundingRule) {
170+
native.round(rule)
171171
}
172172

173-
public var nextDown: CGFloat {
174-
return CGFloat(native.nextDown)
173+
public var nextUp: CGFloat {
174+
return CGFloat(native.nextUp)
175175
}
176176

177177
public static func abs(_ x: CGFloat) -> CGFloat {
@@ -202,8 +202,6 @@ public struct CGFloat {
202202
native.formTruncatingRemainder(dividingBy: other.native)
203203
}
204204

205-
/* TODO: Need to call C sqrt and fma or llvm sqrt and fma intrinsics
206-
* for these to be implemented on the underlying types.
207205
public mutating func formRemainder(dividingBy other: CGFloat) {
208206
native.formRemainder(dividingBy: other.native)
209207
}
@@ -215,7 +213,6 @@ public struct CGFloat {
215213
public mutating func addProduct(_ lhs: CGFloat, _ rhs: CGFloat) {
216214
native.addProduct(lhs.native, rhs.native)
217215
}
218-
*/
219216

220217
public func isEqual(to other: CGFloat) -> Bool {
221218
return self.native.isEqual(to: other.native)

stdlib/public/SwiftShims/LibcShims.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,45 @@ __swift_uint32_t _swift_stdlib_cxx11_mt19937(void);
8282
SWIFT_RUNTIME_STDLIB_INTERFACE
8383
__swift_uint32_t
8484
_swift_stdlib_cxx11_mt19937_uniform(__swift_uint32_t upper_bound);
85+
86+
// Math library functions
87+
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_remainderf(float, float);
88+
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_squareRootf(float);
89+
SWIFT_RUNTIME_STDLIB_INTERFACE
90+
float _swift_stdlib_addProductf(float, float, float);
91+
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_roundf(float);
92+
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_roundevenf(float);
93+
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_truncf(float);
94+
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_roundawayf(float);
95+
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_ceilf(float);
96+
SWIFT_RUNTIME_STDLIB_INTERFACE float _swift_stdlib_floorf(float);
97+
98+
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_remainder(double, double);
99+
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_squareRoot(double);
100+
SWIFT_RUNTIME_STDLIB_INTERFACE
101+
double _swift_stdlib_addProduct(double, double, double);
102+
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_round(double);
103+
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_roundeven(double);
104+
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_trunc(double);
105+
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_roundaway(double);
106+
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_ceil(double);
107+
SWIFT_RUNTIME_STDLIB_INTERFACE double _swift_stdlib_floor(double);
108+
109+
// TODO: Remove horrible workaround when importer does Float80 <-> long double.
110+
#if (defined __i386__ || defined __x86_64__) && !defined _MSC_VER
111+
SWIFT_RUNTIME_STDLIB_INTERFACE
112+
void _swift_stdlib_remainderl(void *_self, const void *_other);
113+
SWIFT_RUNTIME_STDLIB_INTERFACE
114+
void _swift_stdlib_squareRootl(void *_self);
115+
SWIFT_RUNTIME_STDLIB_INTERFACE
116+
void _swift_stdlib_addProductl(void *_self, const void *_lhs, const void *_rhs);
117+
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_roundl(void *_self);
118+
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_roundevenl(void *_self);
119+
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_truncl(void *_self);
120+
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_roundawayl(void *_self);
121+
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_ceill(void *_self);
122+
SWIFT_RUNTIME_STDLIB_INTERFACE void _swift_stdlib_floorl(void *_self);
123+
#endif
85124

86125
#ifdef __cplusplus
87126
}} // extern "C", namespace swift

stdlib/public/core/FloatingPoint.swift.gyb

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,6 @@ public protocol FloatingPoint: Comparable, IntegerLiteralConvertible,
279279
/// representable value.
280280
mutating func divide(by other: Self)
281281

282-
/* TODO: Need a remainder builtin or to call C remainder[fl] for these
283282
/// Remainder of `self` divided by `other`. This is the IEEE 754 remainder
284283
/// operation.
285284
///
@@ -298,7 +297,6 @@ public protocol FloatingPoint: Comparable, IntegerLiteralConvertible,
298297

299298
/// Mutating form of `remainder`.
300299
mutating func formRemainder(dividingBy other: Self)
301-
*/
302300

303301
/// Remainder of `self` divided by `other` using truncating division.
304302
/// Equivalent to the C standard library function `fmod`.
@@ -314,8 +312,6 @@ public protocol FloatingPoint: Comparable, IntegerLiteralConvertible,
314312
/// Mutating form of `truncatingRemainder`.
315313
mutating func formTruncatingRemainder(dividingBy other: Self)
316314

317-
/* TODO: Need to call C sqrt and fma or llvm sqrt and fma intrinsics
318-
* for these.
319315
/// Square root of `self`.
320316
func squareRoot() -> Self
321317

@@ -328,7 +324,6 @@ public protocol FloatingPoint: Comparable, IntegerLiteralConvertible,
328324

329325
/// Fused multiply-add, accumulating the product of `lhs` and `rhs` to `self`.
330326
mutating func addProduct(_ lhs: Self, _ rhs: Self)
331-
*/
332327

333328
/// The minimum of `x` and `y`. Implements the IEEE 754 `minNum` operation.
334329
///
@@ -364,6 +359,35 @@ public protocol FloatingPoint: Comparable, IntegerLiteralConvertible,
364359
/// `y` are quiet NaNs, a quiet NaN is returned.
365360
static func maximumMagnitude(_ x: Self, _ y: Self) -> Self
366361

362+
/// Returns the value of `self` rounded to an integral value using the
363+
/// specified rounding rule. If the rounding rule is omitted, it defaults
364+
/// to `.toNearestOrAwayFromZero`, aka "schoolbook rounding".
365+
///
366+
/// This implements the C library rounding functions and the IEEE 754
367+
/// operations that they bind.
368+
///
369+
/// - `round(x)` is `x.rounded()` (the default rounding rule is provided by
370+
/// an extension. This implements the IEEE 754 `roundToIntegralTiesToAway`
371+
/// operation.
372+
///
373+
/// - `roundeven(x)` is `x.rounded(.toNearestOrEven)`. This implements
374+
/// the IEEE 754 `roundToIntegralTiesToEven` operation.
375+
///
376+
/// - `trunc(x)` is `x.rounded(.towardZero)`. This implements the IEEE 754
377+
/// `roundToIntegralTowardZero` operation.
378+
///
379+
/// - `ceil(x)` is `x.rounded(.up)`. This implements the IEEE 754
380+
/// `roundToIntegralTowardPositive` operation.
381+
///
382+
/// - `floor(x)` is `x.rounded(.down)`. This implements the IEEE 754
383+
/// `roundToIntegralTowardNegative` operation.
384+
func rounded(_ rule: FloatingPointRoundingRule) -> Self
385+
386+
/// Rounds `self` to an integral value using the specified rounding rule.
387+
/// If the rounding rule is omitted, it defaults to
388+
/// `.toNearestOrAwayFromZero`, aka "schoolbook rounding".
389+
mutating func round(_ rule: FloatingPointRoundingRule)
390+
367391
/// The least representable value that compares greater than `self`.
368392
///
369393
/// - If `x` is `-infinity`, then `x.nextUp` is `-greatestMagnitude`.
@@ -490,6 +514,35 @@ public enum FloatingPointClassification {
490514
case positiveInfinity
491515
}
492516

517+
/// Describes a rule for rounding a floating-point number.
518+
public enum FloatingPointRoundingRule {
519+
520+
/// The result is the closest allowed value; if two values are equally close,
521+
/// the one with greater magnitude is chosen. Also known as "schoolbook
522+
/// rounding".
523+
case toNearestOrAwayFromZero
524+
525+
/// The result is the closest allowed value; if two values are equally close,
526+
/// the even one is chosen. Also known as "bankers rounding".
527+
case toNearestOrEven
528+
529+
/// The result is the closest allowed value that is greater than or equal
530+
/// to the source.
531+
case up
532+
533+
/// The result is the closest allowed value that is less than or equal to
534+
/// the source.
535+
case down
536+
537+
/// The result is the closest allowed value whose magnitude is less than or
538+
/// equal to that of the source.
539+
case towardZero
540+
541+
/// The result is the closest allowed value whose magnitude is greater than
542+
/// or equal to that of the source.
543+
case awayFromZero
544+
}
545+
493546
@_transparent
494547
public prefix func +<T : FloatingPoint>(x: T) -> T {
495548
return x
@@ -522,12 +575,10 @@ public func ${op[0]}=<T : FloatingPoint>(lhs: inout T, rhs: T) {
522575

523576
%end
524577

525-
/* TODO: uncomment once implemented.
526578
@_transparent
527579
public func sqrt<T : FloatingPoint>(_ rhs: T) -> T {
528580
return rhs.squareRoot()
529581
}
530-
*/
531582

532583
@_transparent
533584
public func ==<T : FloatingPoint>(lhs: T, rhs: T) -> Bool {
@@ -675,14 +726,47 @@ extension FloatingPoint {
675726
return Self(1).ulp
676727
}
677728

729+
@_transparent
730+
public func rounded(_ rule: FloatingPointRoundingRule) -> Self {
731+
var lhs = self
732+
lhs.round(rule)
733+
return lhs
734+
}
735+
736+
/// Returns `self` rounded to the closest integral value. If `self` is
737+
/// exactly halfway between two integers (e.g. 1.5), the integral value
738+
/// with greater magnitude (2.0 in this example) is returned.
739+
///
740+
/// Other rounding modes can be explicitly specified with
741+
/// `.rounded(_: FloatingPointRoundingRule)`.
742+
@_transparent
743+
public func rounded() -> Self {
744+
return rounded(.toNearestOrAwayFromZero)
745+
}
746+
747+
/// Rounds `self` to the closest integral value. If `self` is exactly
748+
/// halfway between two integers (e.g. 1.5), the integral value with
749+
/// greater magnitude is selected.
750+
///
751+
/// Other rounding modes can be explicitly specified with
752+
/// `.round(_: FloatingPointRoundingRule)`.
753+
@_transparent
754+
public mutating func round() {
755+
round(.toNearestOrAwayFromZero)
756+
}
757+
758+
@_transparent
759+
public var nextDown: Self {
760+
return -(-self).nextUp
761+
}
762+
678763
@_transparent
679764
public func truncatingRemainder(dividingBy rhs: Self) -> Self {
680765
var lhs = self
681766
lhs.formTruncatingRemainder(dividingBy: rhs)
682767
return lhs
683768
}
684769

685-
/* TODO: uncomment once implemented.
686770
@_transparent
687771
public func remainder(dividingBy rhs: Self) -> Self {
688772
var lhs = self
@@ -703,7 +787,6 @@ extension FloatingPoint {
703787
addend.addProduct(lhs, rhs)
704788
return addend
705789
}
706-
*/
707790

708791
public static func minimum(_ left: Self, _ right: Self) -> Self {
709792
if left.isSignalingNaN || right.isSignalingNaN {

stdlib/public/core/FloatingPointTypes.swift.gyb

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,39 @@ extension ${Self}: BinaryFloatingPoint {
508508
significandBitPattern: significandBitPattern + 1)
509509
}
510510

511-
public var nextDown: ${Self} {
512-
return -(-self).nextUp
511+
@_transparent
512+
public mutating func round(_ rule: FloatingPointRoundingRule) {
513+
%if bits == 80:
514+
switch rule {
515+
case .toNearestOrAwayFromZero:
516+
_swift_stdlib_roundl(&self)
517+
case .toNearestOrEven:
518+
_swift_stdlib_roundevenl(&self)
519+
case .towardZero:
520+
_swift_stdlib_truncl(&self)
521+
case .awayFromZero:
522+
_swift_stdlib_roundawayl(&self)
523+
case .up:
524+
_swift_stdlib_ceill(&self)
525+
case .down:
526+
_swift_stdlib_floorl(&self)
527+
}
528+
%else:
529+
switch rule {
530+
case .toNearestOrAwayFromZero:
531+
self = _swift_stdlib_round${cFuncSuffix(bits)}(self)
532+
case .toNearestOrEven:
533+
self = _swift_stdlib_roundeven${cFuncSuffix(bits)}(self)
534+
case .towardZero:
535+
self = _swift_stdlib_trunc${cFuncSuffix(bits)}(self)
536+
case .awayFromZero:
537+
self = _swift_stdlib_roundaway${cFuncSuffix(bits)}(self)
538+
case .up:
539+
self = _swift_stdlib_ceil${cFuncSuffix(bits)}(self)
540+
case .down:
541+
self = _swift_stdlib_floor${cFuncSuffix(bits)}(self)
542+
}
543+
%end
513544
}
514545

515546
@_transparent
@@ -537,30 +568,40 @@ extension ${Self}: BinaryFloatingPoint {
537568
_value = Builtin.fdiv_FPIEEE${bits}(self._value, other._value)
538569
}
539570

540-
/* TODO: Need a remainder builtin or to call C remainder[fl] for this
541571
@_transparent
542572
public mutating func formRemainder(dividingBy other: ${Self}) {
543-
fatalError("Unimplemented")
573+
%if bits == 80:
574+
var other = other
575+
_swift_stdlib_remainderl(&self, &other)
576+
%else:
577+
self = _swift_stdlib_remainder${cFuncSuffix(bits)}(self, other)
578+
%end
544579
}
545-
*/
546580

547581
@_transparent
548582
public mutating func formTruncatingRemainder(dividingBy other: ${Self}) {
549583
_value = Builtin.frem_FPIEEE${bits}(self._value, other._value)
550584
}
551585

552-
/* TODO: Need to call C sqrt and fma or llvm sqrt and fma intrinsics
553-
* for these.
554586
@_transparent
555587
public mutating func formSquareRoot( ) {
556-
fatalError("Unimplemented.")
588+
%if bits == 80:
589+
_swift_stdlib_squareRootl(&self)
590+
%else:
591+
self = _swift_stdlib_squareRoot${cFuncSuffix(bits)}(self)
592+
%end
557593
}
558594

559595
@_transparent
560596
public mutating func addProduct(_ lhs: ${Self}, _ rhs: ${Self}) {
561-
fatalError("Unimplemented.")
597+
%if bits == 80:
598+
var lhs = lhs
599+
var rhs = rhs
600+
_swift_stdlib_addProductl(&self, &lhs, &rhs)
601+
%else:
602+
self = _swift_stdlib_addProduct${cFuncSuffix(bits)}(self, lhs, rhs)
603+
%end
562604
}
563-
*/
564605

565606
@_transparent
566607
public func isEqual(to other: ${Self}) -> Bool {

0 commit comments

Comments
 (0)