Add tie-breaking exponentiation operators and tests
This commit is contained in:
parent
16d65fca54
commit
23f5c7a496
12
README.md
12
README.md
|
@ -59,6 +59,18 @@ add the package as a dependency. See Swift documentation for details.
|
||||||
```swift
|
```swift
|
||||||
import NumericAnnex
|
import NumericAnnex
|
||||||
|
|
||||||
|
print(2 ** 3)
|
||||||
|
// Prints "8".
|
||||||
|
|
||||||
|
print(4.0 ** 5.0)
|
||||||
|
// Prints "1024.0".
|
||||||
|
|
||||||
|
print(Int.cbrt(8))
|
||||||
|
// Prints "2".
|
||||||
|
|
||||||
|
print(Double.cbrt(27.0))
|
||||||
|
// Prints "3.0".
|
||||||
|
|
||||||
var x: Ratio = 1 / 4
|
var x: Ratio = 1 / 4
|
||||||
// Ratio is a type alias for Rational<Int>.
|
// Ratio is a type alias for Rational<Int>.
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ extension BinaryInteger {
|
||||||
// MARK: Exponentiation
|
// MARK: Exponentiation
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
// We need to factor out the implementation of `**` so that the tie-breaking
|
||||||
/// representable value.
|
// operators implemented in extensions to concrete integer types can call it.
|
||||||
@_transparent // @_inlineable
|
@_versioned
|
||||||
public static func ** (lhs: Self, rhs: Self) -> Self {
|
internal static func _pow(_ lhs: Self, _ rhs: Self) -> Self {
|
||||||
var x = lhs, n = rhs
|
var x = lhs, n = rhs
|
||||||
if Self.isSigned && n < 0 {
|
if Self.isSigned && n < 0 {
|
||||||
x = 1 / x
|
x = 1 / x
|
||||||
|
@ -34,6 +34,13 @@ extension BinaryInteger {
|
||||||
return x * y
|
return x * y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: Self, rhs: Self) -> Self {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
/// to a representable value.
|
/// to a representable value.
|
||||||
@_transparent // @_inlineable
|
@_transparent // @_inlineable
|
||||||
|
@ -230,3 +237,233 @@ where Self : FixedWidthInteger,
|
||||||
return (Self(t.high), t.low)
|
return (Self(t.high), t.low)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// TIE-BREAKING OPERATORS
|
||||||
|
//
|
||||||
|
// The following extensions are required so that an expression such as `2 ** 3`
|
||||||
|
// is unambiguous as long as `IntegerLiteralType` is one of the standard library
|
||||||
|
// types below.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
extension Int {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: Int, rhs: Int) -> Int {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout Int, rhs: Int) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Int8 {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: Int8, rhs: Int8) -> Int8 {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout Int8, rhs: Int8) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Int16 {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: Int16, rhs: Int16) -> Int16 {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout Int16, rhs: Int16) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Int32 {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: Int32, rhs: Int32) -> Int32 {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout Int32, rhs: Int32) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Int64 {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: Int64, rhs: Int64) -> Int64 {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout Int64, rhs: Int64) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UInt {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: UInt, rhs: UInt) -> UInt {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout UInt, rhs: UInt) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UInt8 {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: UInt8, rhs: UInt8) -> UInt8 {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout UInt8, rhs: UInt8) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UInt16 {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: UInt16, rhs: UInt16) -> UInt16 {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout UInt16, rhs: UInt16) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UInt32 {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: UInt32, rhs: UInt32) -> UInt32 {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout UInt32, rhs: UInt32) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UInt64 {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: UInt64, rhs: UInt64) -> UInt64 {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout UInt64, rhs: UInt64) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if false
|
||||||
|
extension DoubleWidth {
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// MARK: Exponentiation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Returns the result of raising `lhs` to the power of `rhs`, rounded to a
|
||||||
|
/// representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func ** (lhs: DoubleWidth, rhs: DoubleWidth) -> DoubleWidth {
|
||||||
|
return _pow(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises `lhs` to the power of `rhs` and stores the result in `lhs`, rounded
|
||||||
|
/// to a representable value.
|
||||||
|
@_transparent // @_inlineable
|
||||||
|
public static func **= (lhs: inout DoubleWidth, rhs: DoubleWidth) {
|
||||||
|
lhs = lhs ** rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -2,6 +2,7 @@ import XCTest
|
||||||
@testable import NumericAnnexTests
|
@testable import NumericAnnexTests
|
||||||
|
|
||||||
XCTMain([
|
XCTMain([
|
||||||
|
testCase(DocumentationExampleTests.allTests),
|
||||||
testCase(ExponentiationTests.allTests),
|
testCase(ExponentiationTests.allTests),
|
||||||
testCase(RootExtractionTests.allTests),
|
testCase(RootExtractionTests.allTests),
|
||||||
testCase(FactoringTests.allTests),
|
testCase(FactoringTests.allTests),
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
import XCTest
|
||||||
|
/* @testable */ import NumericAnnex
|
||||||
|
|
||||||
|
class DocumentationExampleTests : XCTestCase {
|
||||||
|
// It reflects poorly on the project to provide examples that don't compile or
|
||||||
|
// give the wrong result, so test them here:
|
||||||
|
|
||||||
|
func testReadmeExample() {
|
||||||
|
print(2 ** 3)
|
||||||
|
// Prints "8".
|
||||||
|
XCTAssertEqual("\(2 ** 3)", "8")
|
||||||
|
|
||||||
|
print(4.0 ** 5.0)
|
||||||
|
// Prints "1024.0".
|
||||||
|
XCTAssertEqual("\(4.0 ** 5.0)", "1024.0")
|
||||||
|
|
||||||
|
print(Int.cbrt(8))
|
||||||
|
// Prints "2".
|
||||||
|
XCTAssertEqual("\(Int.cbrt(8))", "2")
|
||||||
|
|
||||||
|
print(Double.cbrt(27.0))
|
||||||
|
// Prints "3.0".
|
||||||
|
XCTAssertEqual("\(Double.cbrt(27.0))", "3.0")
|
||||||
|
|
||||||
|
var x: Ratio = 1 / 4
|
||||||
|
// Ratio is a type alias for Rational<Int>.
|
||||||
|
|
||||||
|
print(x.reciprocal())
|
||||||
|
// Prints "4".
|
||||||
|
XCTAssertEqual("\(x.reciprocal())", "4")
|
||||||
|
|
||||||
|
x *= 8
|
||||||
|
print(x + x)
|
||||||
|
// Prints "4".
|
||||||
|
XCTAssertEqual("\(x + x)", "4")
|
||||||
|
|
||||||
|
x = Ratio(Float.phi) // Golden ratio.
|
||||||
|
print(x)
|
||||||
|
// Prints "13573053/8388608".
|
||||||
|
XCTAssertEqual("\(x)", "13573053/8388608")
|
||||||
|
|
||||||
|
var z: Complex64 = 42 * .i
|
||||||
|
// Complex64 is a type alias for Complex<Float>.
|
||||||
|
|
||||||
|
print(Complex.sqrt(z))
|
||||||
|
// Prints "4.58258 + 4.58258i".
|
||||||
|
XCTAssertEqual("\(Complex.sqrt(z))", "4.58258 + 4.58258i")
|
||||||
|
|
||||||
|
z = .pi + .i * .log(2 - .sqrt(3))
|
||||||
|
print(Complex.cos(z).real)
|
||||||
|
// Prints "-2.0".
|
||||||
|
XCTAssertEqual("\(Complex.cos(z).real)", "-2.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
static var allTests = [
|
||||||
|
("testReadmeExample", testReadmeExample),
|
||||||
|
]
|
||||||
|
}
|
|
@ -27,8 +27,47 @@ class ExponentiationTests : XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testConcreteIntegerTypePow() {
|
||||||
|
XCTAssertEqual((2 as Int) ** 3, 8 as Int)
|
||||||
|
XCTAssertEqual((2 as Int8) ** 3, 8 as Int8)
|
||||||
|
XCTAssertEqual((2 as Int16) ** 3, 8 as Int16)
|
||||||
|
XCTAssertEqual((2 as Int32) ** 3, 8 as Int32)
|
||||||
|
XCTAssertEqual((2 as Int64) ** 3, 8 as Int64)
|
||||||
|
|
||||||
|
do { var x = 2 as Int; x **= 3; XCTAssertEqual(x, 8 as Int) }
|
||||||
|
do { var x = 2 as Int8; x **= 3; XCTAssertEqual(x, 8 as Int8) }
|
||||||
|
do { var x = 2 as Int16; x **= 3; XCTAssertEqual(x, 8 as Int16) }
|
||||||
|
do { var x = 2 as Int32; x **= 3; XCTAssertEqual(x, 8 as Int32) }
|
||||||
|
do { var x = 2 as Int64; x **= 3; XCTAssertEqual(x, 8 as Int64) }
|
||||||
|
|
||||||
|
XCTAssertEqual((2 as UInt) ** 3, 8 as UInt)
|
||||||
|
XCTAssertEqual((2 as UInt8) ** 3, 8 as UInt8)
|
||||||
|
XCTAssertEqual((2 as UInt16) ** 3, 8 as UInt16)
|
||||||
|
XCTAssertEqual((2 as UInt32) ** 3, 8 as UInt32)
|
||||||
|
XCTAssertEqual((2 as UInt64) ** 3, 8 as UInt64)
|
||||||
|
|
||||||
|
do { var x = 2 as UInt; x **= 3; XCTAssertEqual(x, 8 as UInt) }
|
||||||
|
do { var x = 2 as UInt8; x **= 3; XCTAssertEqual(x, 8 as UInt8) }
|
||||||
|
do { var x = 2 as UInt16; x **= 3; XCTAssertEqual(x, 8 as UInt16) }
|
||||||
|
do { var x = 2 as UInt32; x **= 3; XCTAssertEqual(x, 8 as UInt32) }
|
||||||
|
do { var x = 2 as UInt64; x **= 3; XCTAssertEqual(x, 8 as UInt64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGenericIntegerTypePow() {
|
||||||
|
func _testPow<
|
||||||
|
T : BinaryInteger
|
||||||
|
>(_: T.Type = T.self, lhs: T, rhs: T, expected: T) {
|
||||||
|
XCTAssertEqual(lhs ** rhs, expected)
|
||||||
|
do { var x = lhs; x **= rhs; XCTAssertEqual(x, expected) }
|
||||||
|
}
|
||||||
|
_testPow(lhs: 2 as Int, rhs: 3, expected: 8)
|
||||||
|
_testPow(lhs: 2 as UInt, rhs: 3, expected: 8)
|
||||||
|
}
|
||||||
|
|
||||||
static var allTests = [
|
static var allTests = [
|
||||||
("testIntPow", testIntPow),
|
("testIntPow", testIntPow),
|
||||||
("testUIntPow", testUIntPow),
|
("testUIntPow", testUIntPow),
|
||||||
|
("testConcreteIntegerTypePow", testConcreteIntegerTypePow),
|
||||||
|
("testGenericIntegerTypePow", testGenericIntegerTypePow),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue