Skip to content
Merged
Show file tree
Hide file tree
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
4 changes: 3 additions & 1 deletion Sources/Complex/Arithmetic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
//
//===----------------------------------------------------------------------===//

import Real

// MARK: - Additive structure
extension Complex: AdditiveArithmetic {
@_transparent
Expand Down Expand Up @@ -62,7 +64,7 @@ extension Complex {
}

// MARK: - Multiplicative structure
extension Complex: Numeric {
extension Complex: AlgebraicField {
@_transparent
public static func *(z: Complex, w: Complex) -> Complex {
return Complex(z.x*w.x - z.y*w.y, z.x*w.y + z.y*w.x)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Complex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This module provides a `Complex` number type generic over an underlying `RealTyp
```
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).

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`).
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`).

### Dependencies:
- The `Real` module.
Expand Down
85 changes: 85 additions & 0 deletions Sources/Real/AlgebraicField.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//===--- AlgebraicField.swift ---------------------------------*- swift -*-===//
//
// This source file is part of the Swift Numerics open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

/// A type modeling an algebraic [field]. Refines the `Numeric` protocol,
/// adding division.
///
/// A field is a set on which addition, subtraction, multiplication, and
/// division are defined, and behave basically like those operations on
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// division are defined, and behave basically like those operations on
/// division are defined, and behaves basically like those operations on

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Behave" is correct here; the subject is "addition, subtraction, ... and division".

/// the real numbers. More precisely, a field is a commutative group under
/// its addition, the non-zero elements of the field form a commutative
/// group under its multiplication, and the distributitve law holds.
///
/// Some common examples of fields include:
///
/// - the rational numbers
/// - the real numbers
/// - the complex numbers
/// - the integers modulo a prime
///
/// The most familiar example of a thing that is *not* a field is the integers.
/// This may be surprising, since integers seem to have addition, subtraction,
/// multiplication and division. Why don't they form a field?
///
/// Because integer multiplication does not form a group; it's commutative and
/// associative, but integers do not have multiplicative inverses.
/// I.e. if a is any integer other than 1 or -1, there is no integer b such
/// that a*b = 1. The existence of inverses is requried to form a field.
///
/// If a type `T` conforms to the `Real` protocol, then `T` and `Complex<T>`
/// both conform to `AlgebraicField`.
///
/// See Also:
/// -
/// - Real
/// - Numeric
/// - AdditiveArithmetic
///
/// [field]: https://en.wikipedia.org/wiki/Field_(mathematics)
public protocol AlgebraicField: Numeric {

static func /=(a: inout Self, b: Self)

static func /(a: Self, b: Self) -> Self

/// The (approximate) reciprocal (multiplicative inverse) of this number,
/// if it is representable.
///
/// If reciprocal is non-nil, you can replace division by self with
/// multiplication by reciprocal and either get exact the same result
/// (for finite fields) or approximately the same result up to a typical
/// rounding error (for floating-point formats).
///
/// If self is zero, or if a reciprocal would overflow or underflow such
/// that it cannot be accurately represented, the result is nil. Note that
/// `.zero.reciprocal`, somewhat surprisingly, is *not* nil for `Real` or
/// `Complex` types, because these types have an `.infinity` value that
/// acts as the reciprocal of `.zero`.
var reciprocal: Self? { get }
}

extension AlgebraicField {
@_transparent
public static func /(a: Self, b: Self) -> Self {
var result = a
result /= b
return result
}

/// Implementations should be *conservative* with the reciprocal property;
/// it is OK to return `nil` even in cases where a reciprocal could be
/// represented. For this reason, a default implementation that simply
/// always returns `nil` is correct, but conforming types should provide
/// a better implementation if possible.
public var reciprocal: Self? {
return nil
}
}
6 changes: 5 additions & 1 deletion Sources/Real/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The `Real` module provides that API as a separate module so that you can use it

## Protocols and Methods

The module defines three protocols. The most general is `ElementaryFunctions`, which makes the following functions available:
The module defines four protocols. The most general is `ElementaryFunctions`, which makes the following functions available:
- Exponential functions: `exp`, `expMinusOne`
- Logarithmic functions: `log`, `log(onePlus:)`
- Trigonometric functions: `cos`, `sin`, `tan`
Expand All @@ -28,6 +28,9 @@ The `RealFunctions` protocol refines `ElementaryFunctions`, and adds operations
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.
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.

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.
The primary use of this protocol is for writing code that is generic over real and complex types.

## Using Real

First, either import `Real` directly or import the `Numerics` umbrella module.
Expand Down Expand Up @@ -70,3 +73,4 @@ Not having this protocol is a significant missing feature for numerical computin
[ErrorFunction]: https://en.wikipedia.org/wiki/Error_function
[GammaFunction]: https://en.wikipedia.org/wiki/Gamma_function
[SE-0246]: https://github.com/apple/swift-evolution/blob/master/proposals/0246-mathable.md
[Sigmoid]: https://en.wikipedia.org/wiki/Sigmoid_function
12 changes: 11 additions & 1 deletion Sources/Real/Real.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
/// -
/// - `ElementaryFunctions`
/// - `RealFunctions`
public protocol Real: FloatingPoint, RealFunctions {
/// - `AlgebraicField`
public protocol Real: FloatingPoint, RealFunctions, AlgebraicField {
}

// While `Real` does not provide any additional customization points,
Expand Down Expand Up @@ -79,4 +80,13 @@ extension Real {
public static func sqrt(_ x: Self) -> Self {
return x.squareRoot()
}

@inlinable
public var reciprocal: Self? {
let recip = 1/self
if recip.isNormal || isZero || !isFinite {
return recip
}
return nil
}
}