Skip to content

Commit 7bd2909

Browse files
Merge pull request #91 from apple/FieldProtocol
Introduce AlgebraicField protocol
2 parents f3e1e15 + 323542c commit 7bd2909

File tree

5 files changed

+105
-4
lines changed

5 files changed

+105
-4
lines changed

Sources/Complex/Arithmetic.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
//
1010
//===----------------------------------------------------------------------===//
1111

12+
import Real
13+
1214
// MARK: - Additive structure
1315
extension Complex: AdditiveArithmetic {
1416
@_transparent
@@ -62,7 +64,7 @@ extension Complex {
6264
}
6365

6466
// MARK: - Multiplicative structure
65-
extension Complex: Numeric {
67+
extension Complex: AlgebraicField {
6668
@_transparent
6769
public static func *(z: Complex, w: Complex) -> Complex {
6870
return Complex(z.x*w.x - z.y*w.y, z.x*w.y + z.y*w.x)

Sources/Complex/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This module provides a `Complex` number type generic over an underlying `RealTyp
77
```
88
This module provides approximate feature parity and memory layout compatibility with C, Fortran, and C++ complex types (although the importer cannot map the types for you, buffers may be reinterpreted to shim API defined in other languages).
99

10-
The usual arithmetic operators are provided for Complex numbers, as well as conversion to and from polar coordinates and many useful properties, plus conformances to the obvious usual protocols: `Equatable`, `Hashable`, `Codable` (if the underlying `RealType` is), and `Numeric` (hence also `AdditiveArithmetic`).
10+
The usual arithmetic operators are provided for Complex numbers, as well as conversion to and from polar coordinates and many useful properties, plus conformances to the obvious usual protocols: `Equatable`, `Hashable`, `Codable` (if the underlying `RealType` is), and `AlgebraicField` (hence also `AdditiveArithmetic` and `Numeric`).
1111

1212
### Dependencies:
1313
- The `Real` module.

Sources/Real/AlgebraicField.swift

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//===--- AlgebraicField.swift ---------------------------------*- swift -*-===//
2+
//
3+
// This source file is part of the Swift Numerics open source project
4+
//
5+
// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
/// A type modeling an algebraic [field]. Refines the `Numeric` protocol,
13+
/// adding division.
14+
///
15+
/// A field is a set on which addition, subtraction, multiplication, and
16+
/// division are defined, and behave basically like those operations on
17+
/// the real numbers. More precisely, a field is a commutative group under
18+
/// its addition, the non-zero elements of the field form a commutative
19+
/// group under its multiplication, and the distributitve law holds.
20+
///
21+
/// Some common examples of fields include:
22+
///
23+
/// - the rational numbers
24+
/// - the real numbers
25+
/// - the complex numbers
26+
/// - the integers modulo a prime
27+
///
28+
/// The most familiar example of a thing that is *not* a field is the integers.
29+
/// This may be surprising, since integers seem to have addition, subtraction,
30+
/// multiplication and division. Why don't they form a field?
31+
///
32+
/// Because integer multiplication does not form a group; it's commutative and
33+
/// associative, but integers do not have multiplicative inverses.
34+
/// I.e. if a is any integer other than 1 or -1, there is no integer b such
35+
/// that a*b = 1. The existence of inverses is requried to form a field.
36+
///
37+
/// If a type `T` conforms to the `Real` protocol, then `T` and `Complex<T>`
38+
/// both conform to `AlgebraicField`.
39+
///
40+
/// See Also:
41+
/// -
42+
/// - Real
43+
/// - Numeric
44+
/// - AdditiveArithmetic
45+
///
46+
/// [field]: https://en.wikipedia.org/wiki/Field_(mathematics)
47+
public protocol AlgebraicField: Numeric {
48+
49+
static func /=(a: inout Self, b: Self)
50+
51+
static func /(a: Self, b: Self) -> Self
52+
53+
/// The (approximate) reciprocal (multiplicative inverse) of this number,
54+
/// if it is representable.
55+
///
56+
/// If reciprocal is non-nil, you can replace division by self with
57+
/// multiplication by reciprocal and either get exact the same result
58+
/// (for finite fields) or approximately the same result up to a typical
59+
/// rounding error (for floating-point formats).
60+
///
61+
/// If self is zero, or if a reciprocal would overflow or underflow such
62+
/// that it cannot be accurately represented, the result is nil. Note that
63+
/// `.zero.reciprocal`, somewhat surprisingly, is *not* nil for `Real` or
64+
/// `Complex` types, because these types have an `.infinity` value that
65+
/// acts as the reciprocal of `.zero`.
66+
var reciprocal: Self? { get }
67+
}
68+
69+
extension AlgebraicField {
70+
@_transparent
71+
public static func /(a: Self, b: Self) -> Self {
72+
var result = a
73+
result /= b
74+
return result
75+
}
76+
77+
/// Implementations should be *conservative* with the reciprocal property;
78+
/// it is OK to return `nil` even in cases where a reciprocal could be
79+
/// represented. For this reason, a default implementation that simply
80+
/// always returns `nil` is correct, but conforming types should provide
81+
/// a better implementation if possible.
82+
public var reciprocal: Self? {
83+
return nil
84+
}
85+
}

Sources/Real/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The `Real` module provides that API as a separate module so that you can use it
66

77
## Protocols and Methods
88

9-
The module defines three protocols. The most general is `ElementaryFunctions`, which makes the following functions available:
9+
The module defines four protocols. The most general is `ElementaryFunctions`, which makes the following functions available:
1010
- Exponential functions: `exp`, `expMinusOne`
1111
- Logarithmic functions: `log`, `log(onePlus:)`
1212
- Trigonometric functions: `cos`, `sin`, `tan`
@@ -28,6 +28,9 @@ The `RealFunctions` protocol refines `ElementaryFunctions`, and adds operations
2828
The protocol that you will use most often is `Real`, which describes a floating-point type equipped with the full set of basic math functions.
2929
This is a great protocol to use in writing generic code, because it has all the basics that you need to implement most numeric functions.
3030

31+
The fourth protocol is `AlgebraicField`, which `Real` also refines. This protocol is a very small refinement of `Numeric`, adding the `/` and `/=` operators and a `reciprocal` property.
32+
The primary use of this protocol is for writing code that is generic over real and complex types.
33+
3134
## Using Real
3235

3336
First, either import `Real` directly or import the `Numerics` umbrella module.
@@ -70,3 +73,4 @@ Not having this protocol is a significant missing feature for numerical computin
7073
[ErrorFunction]: https://en.wikipedia.org/wiki/Error_function
7174
[GammaFunction]: https://en.wikipedia.org/wiki/Gamma_function
7275
[SE-0246]: https://github.com/apple/swift-evolution/blob/master/proposals/0246-mathable.md
76+
[Sigmoid]: https://en.wikipedia.org/wiki/Sigmoid_function

Sources/Real/Real.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
/// -
2727
/// - `ElementaryFunctions`
2828
/// - `RealFunctions`
29-
public protocol Real: FloatingPoint, RealFunctions {
29+
/// - `AlgebraicField`
30+
public protocol Real: FloatingPoint, RealFunctions, AlgebraicField {
3031
}
3132

3233
// While `Real` does not provide any additional customization points,
@@ -79,4 +80,13 @@ extension Real {
7980
public static func sqrt(_ x: Self) -> Self {
8081
return x.squareRoot()
8182
}
83+
84+
@inlinable
85+
public var reciprocal: Self? {
86+
let recip = 1/self
87+
if recip.isNormal || isZero || !isFinite {
88+
return recip
89+
}
90+
return nil
91+
}
8292
}

0 commit comments

Comments
 (0)