219 lines
7.1 KiB
Swift
219 lines
7.1 KiB
Swift
//
|
|
// IntegerAlgorithms.swift
|
|
// NumericAnnex
|
|
//
|
|
// Created by Xiaodi Wu on 4/15/17.
|
|
//
|
|
|
|
extension BinaryInteger {
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Exponentiation
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// @_transparent // @_inlineable
|
|
/// Returns the result of raising `base` to the power of `exponent`, rounded
|
|
/// to a representable value.
|
|
public static func pow(_ base: Self, _ exponent: Self) -> Self {
|
|
var x = base, n = exponent
|
|
if Self.isSigned && n < 0 {
|
|
x = 1 / x
|
|
n = 0 - n
|
|
} else if n == 0 {
|
|
return 1
|
|
}
|
|
// Exponentiate by iterative squaring.
|
|
var y = 1 as Self
|
|
while n > 1 {
|
|
if n % 2 == 1 {
|
|
y *= x
|
|
n -= 1
|
|
}
|
|
x *= x
|
|
n /= 2
|
|
}
|
|
return x * y
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Square Root
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// @_transparent // @_inlineable
|
|
/// Returns the square root of `x`, rounding toward zero. If `x` is negative,
|
|
/// a runtime error may occur.
|
|
public static func sqrt(_ x: Self) -> Self {
|
|
precondition(!Self.isSigned || x >= 0)
|
|
var shift = x.bitWidth - 1
|
|
shift -= shift % 2
|
|
|
|
var x = x
|
|
var result = 0 as Self
|
|
while shift >= 0 {
|
|
result *= 2
|
|
let temporary = 2 * result + 1
|
|
if temporary <= x >> shift {
|
|
x -= temporary << shift
|
|
result += 1
|
|
}
|
|
shift -= 2
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
extension UnsignedInteger {
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Cube Root
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// @_transparent // @_inlineable
|
|
/// Returns the cube root of `x`, rounding toward zero.
|
|
public static func cbrt(_ x: Self) -> Self {
|
|
var shift = x.bitWidth - 1
|
|
shift -= shift % 3
|
|
|
|
var x = x
|
|
var result = 0 as Self
|
|
while shift >= 0 {
|
|
result *= 2
|
|
let temporary = 3 * result * (result + 1) + 1
|
|
if temporary <= x >> shift {
|
|
x -= temporary << shift
|
|
result += 1
|
|
}
|
|
shift -= 3
|
|
}
|
|
return result
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Factoring
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// @_transparent // @_inlineable
|
|
/// Returns the greatest common divisor of `a` and `b`.
|
|
public static func gcd(_ a: Self, _ b: Self) -> Self {
|
|
// An iterative version of Stein's algorithm.
|
|
if a == 0 { return b } // gcd(0, b) == b
|
|
if b == 0 { return a } // gcd(a, 0) == a
|
|
|
|
var a = a, b = b, shift = 0 as Self
|
|
while ((a | b) & 1) == 0 {
|
|
a >>= 1
|
|
b >>= 1
|
|
shift += 1
|
|
}
|
|
// Now, shift is equal to log2(k), where k is the greatest power of 2
|
|
// dividing a and b.
|
|
while (a & 1) == 0 { a >>= 1 } // Now, a is odd.
|
|
repeat {
|
|
while (b & 1) == 0 { b >>= 1 } // Now, b is odd.
|
|
if a > b { swap(&a, &b) } // Now, a < b.
|
|
b -= a
|
|
} while b != 0
|
|
// Restore common factors of 2.
|
|
return a << shift
|
|
}
|
|
|
|
/// Returns the least common multiple of `a` and `b`.
|
|
@_transparent // @_inlineable
|
|
public static func lcm(_ a: Self, _ b: Self) -> Self {
|
|
if a == 0 || b == 0 { return 0 }
|
|
return a / .gcd(a, b) * b
|
|
}
|
|
}
|
|
|
|
extension UnsignedInteger where Self : FixedWidthInteger {
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Factoring (Fixed-Width)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// @_transparent // @_inlineable
|
|
/// Returns the least common multiple of `a` and `b` and a flag to indicate
|
|
/// whether overflow occurred during the operation.
|
|
public static func lcmReportingOverflow(_ a: Self, _ b: Self)
|
|
-> (partialValue: Self, overflow: Bool) {
|
|
if a == 0 || b == 0 { return (0, false) }
|
|
return (a / .gcd(a, b)).multipliedReportingOverflow(by: b)
|
|
}
|
|
|
|
// @_transparent // @_inlineable
|
|
/// Returns the high and low parts of the least common multiple of `a` and `b`
|
|
/// computed using full-width arithmetic.
|
|
public static func lcmFullWidth(_ a: Self, _ b: Self)
|
|
-> (high: Self, low: Self.Magnitude) {
|
|
if a == 0 || b == 0 { return (0, 0) }
|
|
return (a / .gcd(a, b)).multipliedFullWidth(by: b)
|
|
}
|
|
}
|
|
|
|
extension BinaryInteger where Magnitude : UnsignedInteger {
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Cube Root
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// Returns the cube root of `x`, rounding toward zero.
|
|
@_transparent // @_inlineable
|
|
public static func cbrt(_ x: Self) -> Self {
|
|
return x < 0
|
|
? 0 - Self(Magnitude.cbrt(x.magnitude))
|
|
: Self(Magnitude.cbrt(x.magnitude))
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Factoring
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// Returns the greatest common divisor of `a` and `b`.
|
|
@_transparent // @_inlineable
|
|
public static func gcd(_ a: Self, _ b: Self) -> Self {
|
|
return Self(Magnitude.gcd(a.magnitude, b.magnitude))
|
|
}
|
|
|
|
/// Returns the least common multiple of `a` and `b`.
|
|
@_transparent // @_inlineable
|
|
public static func lcm(_ a: Self, _ b: Self) -> Self {
|
|
return Self(Magnitude.lcm(a.magnitude, b.magnitude))
|
|
}
|
|
}
|
|
|
|
// `BinaryInteger where Self : FixedWidthInteger` may seem superfluous, but it
|
|
// is necessary to disambiguate calls to `Magnitude.lcmReportingOverflow(_:_:)`
|
|
// and `Magnitude.lcmFullWidth(_:_:)`.
|
|
extension BinaryInteger
|
|
where Self : FixedWidthInteger,
|
|
Magnitude : FixedWidthInteger & UnsignedInteger,
|
|
Magnitude.Magnitude == Magnitude {
|
|
// ---------------------------------------------------------------------------
|
|
// MARK: Factoring (Fixed-Width)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// @_transparent // @_inlineable
|
|
/// Returns the greatest common divisor of `a` and `b` and a flag to indicate
|
|
/// whether overflow occurred during the operation.
|
|
public static func gcdReportingOverflow(_ a: Self, _ b: Self)
|
|
-> (partialValue: Self, overflow: Bool) {
|
|
let t = Self(truncatingIfNeeded: Magnitude.gcd(a.magnitude, b.magnitude))
|
|
return (t, t < 0)
|
|
}
|
|
|
|
// @_transparent // @_inlineable
|
|
/// Returns the least common multiple of `a` and `b` and a flag to indicate
|
|
/// whether overflow occurred during the operation.
|
|
public static func lcmReportingOverflow(_ a: Self, _ b: Self)
|
|
-> (partialValue: Self, overflow: Bool) {
|
|
let (t, overflow) = Magnitude.lcmReportingOverflow(a.magnitude, b.magnitude)
|
|
let u = Self(truncatingIfNeeded: t)
|
|
return (u, overflow || u < 0)
|
|
}
|
|
|
|
// @_transparent // @_inlineable
|
|
/// Returns the high and low parts of the least common multiple of `a` and `b`
|
|
/// computed using full-width arithmetic.
|
|
public static func lcmFullWidth(_ a: Self, _ b: Self)
|
|
-> (high: Self, low: Self.Magnitude) {
|
|
let t = Magnitude.lcmFullWidth(a.magnitude, b.magnitude)
|
|
return (Self(t.high), t.low)
|
|
}
|
|
}
|