diff --git a/Sources/TestKit2/Global+Types.swift b/Sources/TestKit2/Global+Types.swift index 3aa265ad..f8146be8 100644 --- a/Sources/TestKit2/Global+Types.swift +++ b/Sources/TestKit2/Global+Types.swift @@ -38,7 +38,7 @@ public let typesAsCoreIntegersAsUnsigned: [any CoreIntegerAsUnsigned.Type] = [ // MARK: + Floats //=----------------------------------------------------------------------------= -public let allSwiftBinaryFloatingPointTypes: [any Swift.BinaryFloatingPoint.Type] = [ +public let typesAsSwiftBinaryFloatingPoint: [any Swift.BinaryFloatingPoint.Type] = [ Float32.self, Float64.self, ] diff --git a/Sources/TestKit2/Utilities+Sign.swift b/Sources/TestKit2/Utilities+Sign.swift new file mode 100644 index 00000000..035ca003 --- /dev/null +++ b/Sources/TestKit2/Utilities+Sign.swift @@ -0,0 +1,23 @@ +//=----------------------------------------------------------------------------= +// This source file is part of the Ultimathnum open source project. +// +// Copyright (c) 2023 Oscar Byström Ericsson +// Licensed under Apache License, Version 2.0 +// +// See http://www.apache.org/licenses/LICENSE-2.0 for license information. +//=----------------------------------------------------------------------------= + +import CoreKit + +//*============================================================================* +// MARK: * Utilities x Sign +//*============================================================================* + +extension Sign { + + //=------------------------------------------------------------------------= + // MARK: Metadata + //=------------------------------------------------------------------------= + + public static let all: [Self] = [plus, minus] +} diff --git a/Tests/StdlibIntKitTests/StdlibInt+Floats.swift b/Tests/StdlibIntKitTests/StdlibInt+Floats.swift index c95b65f8..abc58e92 100644 --- a/Tests/StdlibIntKitTests/StdlibInt+Floats.swift +++ b/Tests/StdlibIntKitTests/StdlibInt+Floats.swift @@ -33,8 +33,10 @@ import TestKit2 // MARK: Tests x Swift.BinaryFloatingPoint //=------------------------------------------------------------------------= - @Test("StdlibInt ← Swift.BinaryFloatingPoint - nan is nil", arguments: allSwiftBinaryFloatingPointTypes) - func initSwiftBinaryFloatingPointNanIsNil(type: any Swift.BinaryFloatingPoint.Type) { + @Test( + "StdlibInt ← Swift.BinaryFloatingPoint - nan is nil", + arguments: typesAsSwiftBinaryFloatingPoint + ) func initSwiftBinaryFloatingPointNanIsNil(type: any Swift.BinaryFloatingPoint.Type) { whereIs(type) func whereIs(_ type: T.Type) where T: Swift.BinaryFloatingPoint { @@ -43,8 +45,10 @@ import TestKit2 } } - @Test("StdlibInt ← Swift.BinaryFloatingPoint - infinity is nil", arguments: allSwiftBinaryFloatingPointTypes) - func initSwiftBinaryFloatingPointInfinityIsNil(type: any Swift.BinaryFloatingPoint.Type) { + @Test( + "StdlibInt ← Swift.BinaryFloatingPoint - infinity is nil", + arguments: typesAsSwiftBinaryFloatingPoint + ) func initSwiftBinaryFloatingPointInfinityIsNil(type: any Swift.BinaryFloatingPoint.Type) { whereIs(type) func whereIs(_ type: T.Type) where T: Swift.BinaryFloatingPoint { @@ -53,8 +57,10 @@ import TestKit2 } } - @Test("StdlibInt ← Swift.BinaryFloatingPoint - rounds towards zero", arguments: allSwiftBinaryFloatingPointTypes) - func initSwiftBinaryFloatingPointRoundsTowardsZero(type: any Swift.BinaryFloatingPoint.Type) { + @Test( + "StdlibInt ← Swift.BinaryFloatingPoint - rounds towards zero", + arguments: typesAsSwiftBinaryFloatingPoint + ) func initSwiftBinaryFloatingPointRoundsTowardsZero(type: any Swift.BinaryFloatingPoint.Type) { whereIs(type) func whereIs(_ type: T.Type) where T: Swift.BinaryFloatingPoint { @@ -128,8 +134,10 @@ import TestKit2 /// 1111111111111111111111111111111111111111111111111110110011000011 → /// 1111111111111111111111111111111111111111111111111111110011000011 → /// - @Test("StdlibInt ← Swift.BinaryFloatingPoint - [large][negative]", arguments: allSwiftBinaryFloatingPointTypes) - func initLargeNegativeFloats(source: any Swift.BinaryFloatingPoint.Type) { + @Test( + "StdlibInt ← Swift.BinaryFloatingPoint - [large][negative]", + arguments: typesAsSwiftBinaryFloatingPoint + ) func initLargeNegativeFloats(source: any Swift.BinaryFloatingPoint.Type) { whereIs(source: source, exponents: 32, steps: source.significandBitCount) func whereIs(source: T.Type, exponents: Int, steps: Int) where T: Swift.BinaryFloatingPoint { @@ -165,8 +173,10 @@ import TestKit2 /// 0110000000000000000000000000000000000000000000000000110011000011 → /// 1110000000000000000000000000000000000000000000000000110011000011 → /// - @Test("StdlibInt ← Swift.BinaryFloatingPoint - [large][negative][min]", arguments: allSwiftBinaryFloatingPointTypes) - func initLargeNegativeFloatsNearMinSignificandBitPattern(source: any Swift.BinaryFloatingPoint.Type) { + @Test( + "StdlibInt ← Swift.BinaryFloatingPoint - [large][negative][min]", + arguments: typesAsSwiftBinaryFloatingPoint + ) func initLargeNegativeFloatsNearMinSignificandBitPattern(source: any Swift.BinaryFloatingPoint.Type) { whereIs(source: source, exponents: 32, steps: 32) func whereIs(source: T.Type, exponents: Int, steps: Int) where T: Swift.BinaryFloatingPoint { @@ -200,8 +210,10 @@ import TestKit2 /// 1001111111111111111111111111111111111111111111111111110011000011 → /// 0001111111111111111111111111111111111111111111111111110011000011 → /// - @Test("StdlibInt ← Swift.BinaryFloatingPoint - [large][negative][max]", arguments: allSwiftBinaryFloatingPointTypes) - func initLargeNegativeFloatsNearMaxSignificandBitPattern(source: any Swift.BinaryFloatingPoint.Type) { + @Test( + "StdlibInt ← Swift.BinaryFloatingPoint - [large][negative][max]", + arguments: typesAsSwiftBinaryFloatingPoint + ) func initLargeNegativeFloatsNearMaxSignificandBitPattern(source: any Swift.BinaryFloatingPoint.Type) { whereIs(source: source, exponents: 32, steps: 32) func whereIs(source: T.Type, exponents: Int, steps: Int) where T: Swift.BinaryFloatingPoint { @@ -235,8 +247,10 @@ import TestKit2 /// 1111111111111111111111111111111111111111111111111110110011000010 → /// 1111111111111111111111111111111111111111111111111111110011000010 → /// - @Test("StdlibInt ← Swift.BinaryFloatingPoint - [large][positive]", arguments: allSwiftBinaryFloatingPointTypes) - func initLargePositiveFloats(source: any Swift.BinaryFloatingPoint.Type) { + @Test( + "StdlibInt ← Swift.BinaryFloatingPoint - [large][positive]", + arguments: typesAsSwiftBinaryFloatingPoint + ) func initLargePositiveFloats(source: any Swift.BinaryFloatingPoint.Type) { whereIs(source: source, exponents: 32, steps: source.significandBitCount) func whereIs(source: T.Type, exponents: Int, steps: Int) where T: Swift.BinaryFloatingPoint { @@ -272,8 +286,10 @@ import TestKit2 /// 0110000000000000000000000000000000000000000000000000110011000010 → /// 1110000000000000000000000000000000000000000000000000110011000010 → /// - @Test("StdlibInt ← Swift.BinaryFloatingPoint - [large][positive][min]", arguments: allSwiftBinaryFloatingPointTypes) - func initLargePositiveFloatsNearMinSignificandBitPattern(source: any Swift.BinaryFloatingPoint.Type) { + @Test( + "StdlibInt ← Swift.BinaryFloatingPoint - [large][positive][min]", + arguments: typesAsSwiftBinaryFloatingPoint + ) func initLargePositiveFloatsNearMinSignificandBitPattern(source: any Swift.BinaryFloatingPoint.Type) { whereIs(source: source, exponents: 32, steps: 32) func whereIs(source: T.Type, exponents: Int, steps: Int) where T: Swift.BinaryFloatingPoint { @@ -307,8 +323,10 @@ import TestKit2 /// 1001111111111111111111111111111111111111111111111111110011000010 → /// 0001111111111111111111111111111111111111111111111111110011000010 → /// - @Test("StdlibInt ← Swift.BinaryFloatingPoint - [large][positive][max]", arguments: allSwiftBinaryFloatingPointTypes) - func initLargePositiveFloatsNearMaxSignificandBitPattern(source: any Swift.BinaryFloatingPoint.Type) { + @Test( + "StdlibInt ← Swift.BinaryFloatingPoint - [large][positive][max]", + arguments: typesAsSwiftBinaryFloatingPoint + ) func initLargePositiveFloatsNearMaxSignificandBitPattern(source: any Swift.BinaryFloatingPoint.Type) { whereIs(source: source, exponents: 32, steps: 32) func whereIs(source: T.Type, exponents: Int, steps: Int) where T: Swift.BinaryFloatingPoint { diff --git a/Tests/UltimathnumTests/BinaryInteger+Floats.swift b/Tests/UltimathnumTests/BinaryInteger+Floats.swift index 65b2cbe1..766ee408 100644 --- a/Tests/UltimathnumTests/BinaryInteger+Floats.swift +++ b/Tests/UltimathnumTests/BinaryInteger+Floats.swift @@ -8,158 +8,260 @@ //=----------------------------------------------------------------------------= import CoreKit -import DoubleIntKit import InfiniIntKit import RandomIntKit -import TestKit +import TestKit2 //*============================================================================* -// MARK: * Binary Integer x Floats +// MARK: * Binary Integer x Floats x Samples //*============================================================================* -final class BinaryIntegerTestsOnFloats: XCTestCase { +@Suite(.serialized, .tags(.generic)) struct BinaryIntegerTestsOnFloatsSamples { //=------------------------------------------------------------------------= - // MARK: Tests + // MARK: Metadata //=------------------------------------------------------------------------= - func testInitFloatRoundsTowardsZero() { - func whereIs(source: A.Type, destination: B.Type) where A: Swift.BinaryFloatingPoint, B: BinaryInteger { - Test().stdlib(A( 0.00), is: 0 as B, exactly: true) - Test().stdlib(A( 0.25), is: 0 as B) - Test().stdlib(A( 0.50), is: 0 as B) - Test().stdlib(A( 0.75), is: 0 as B) - Test().stdlib(A( 1.00), is: 1 as B, exactly: true) - Test().stdlib(A( 1.25), is: 1 as B) - Test().stdlib(A( 1.50), is: 1 as B) - Test().stdlib(A( 1.75), is: 1 as B) - Test().stdlib(A( 2.00), is: 2 as B, exactly: true) - Test().stdlib(A( 2.25), is: 2 as B) - Test().stdlib(A( 2.50), is: 2 as B) - Test().stdlib(A( 2.75), is: 2 as B) - Test().stdlib(A( 3.00), is: 3 as B, exactly: true) - - Test().stdlib(A(-0.00), is: 0 as B, exactly: true) - Test().stdlib(A(-0.25), is: 0 as B) - Test().stdlib(A(-0.50), is: 0 as B) - Test().stdlib(A(-0.75), is: 0 as B) - Test().stdlib(A(-1.00), is: B.isSigned ? -1 as B : nil, exactly: true) - Test().stdlib(A(-1.25), is: B.isSigned ? -1 as B : nil) - Test().stdlib(A(-1.50), is: B.isSigned ? -1 as B : nil) - Test().stdlib(A(-1.75), is: B.isSigned ? -1 as B : nil) - Test().stdlib(A(-2.00), is: B.isSigned ? -2 as B : nil, exactly: true) - Test().stdlib(A(-2.25), is: B.isSigned ? -2 as B : nil) - Test().stdlib(A(-2.50), is: B.isSigned ? -2 as B : nil) - Test().stdlib(A(-2.75), is: B.isSigned ? -2 as B : nil) - Test().stdlib(A(-3.00), is: B.isSigned ? -3 as B : nil, exactly: true) - - Test().stdlib( A.pi, is: 3 as B) - Test().stdlib(-A.pi, is: B.isSigned ? -3 as B : nil) - - Test().stdlib( A.ulpOfOne, is: B.zero) - Test().stdlib(-A.ulpOfOne, is: B.zero) - - Test().stdlib( A.leastNormalMagnitude, is: B.zero) - Test().stdlib(-A.leastNormalMagnitude, is: B.zero) - - Test().stdlib( A.leastNonzeroMagnitude, is: B.zero) - Test().stdlib(-A.leastNonzeroMagnitude, is: B.zero) - } + static let naturals: [(Float64, IXL)] = [ - for source in typesAsSwiftBinaryFloatingPoint { - for destination in typesAsBinaryInteger { - whereIs(source: source, destination: destination) - } + (Float64( 0.0), IXL(0)), + (Float64( 1.0), IXL(1)), + (Float64( 2.0), IXL(2)), + (Float64( 3.0), IXL(3)), + (Float64( 4.0), IXL(4)), + (Float64( 5.0), IXL(5)), + (Float64( 6.0), IXL(6)), + (Float64( 7.0), IXL(7)), + (Float64( 8.0), IXL(8)), + (Float64( 9.0), IXL(9)), + + (Float64( 127.0), IXL(I8 .max)), + (Float64( 128.0), IXL(U8 .msb)), + (Float64( 255.0), IXL(U8 .max)), + (Float64( 32767.0), IXL(I16.max)), + (Float64( 32768.0), IXL(U16.msb)), + (Float64( 65535.0), IXL(U16.max)), + (Float64(2147483647.0), IXL(I32.max)), + (Float64(2147483648.0), IXL(U32.msb)), + (Float64(4294967295.0), IXL(U32.max)), + + (Float64( 1.0), IXL( 1)), + (Float64( 12.0), IXL( 12)), + (Float64( 123.0), IXL( 123)), + (Float64( 1234.0), IXL( 1234)), + (Float64( 12345.0), IXL( 12345)), + (Float64( 123456.0), IXL( 123456)), + (Float64( 1234567.0), IXL( 1234567)), + (Float64( 12345678.0), IXL( 12345678)), + (Float64( 123456789.0), IXL( 123456789)), + (Float64(1234567890.0), IXL(1234567890)), + + (Float64(Float32.greatestFiniteMagnitude), IXL(""" + 0000000000000000000000000340282346638528859811704183484516925440 + """)!), + + (Float64(Float64.greatestFiniteMagnitude), IXL(""" + 0000000000017976931348623157081452742373170435679807056752584499\ + 6598917476803157260780028538760589558632766878171540458953514382\ + 4642343213268894641827684675467035375169860499105765512820762454\ + 9009038932894407586850845513394230458323690322294816580855933212\ + 3348274797826204144723168738177180919299881250404026184124858368 + """)!), + + ] + + static let integers: [(Float64, IXL)] = { + Self.naturals + + Self.naturals.map({( -$0.0, -$0.1 )}) + }() + + static let integersButOneFractionalStepAwayFromZero: [(Float64, Fallible)] = Self.integers.compactMap { a, b in + if a.ulp >= 1 { + return nil + } else if b.isNegative { + return (a - a.ulp, b.veto()) + } else { + return (a + a.ulp, b.veto()) } } - func testInitFloatNanIsNil() { - func whereIs(source: A.Type, destination: B.Type) where A: Swift.BinaryFloatingPoint, B: BinaryInteger { - Test().stdlib( A.nan, is: Optional.none) - Test().stdlib(-A.nan, is: Optional.none) + static let integersButOneFractionalStepTowardsZero: [(Float64, Fallible)] = Self.integers.compactMap { a, b in + if b.isZero { + return nil + } else if a.ulp >= 1 { + return nil + } else if b.isNegative { + return (a + a.ulp, b.incremented().veto()) + } else { + return (a - a.ulp, b.decremented().veto()) + } + } + + static let nonresults: [Float64] = { + var result = [Float64]() + + result.append( Float64.infinity) + result.append(-Float64.infinity) + + for nan: UInt64 in 0..<2 { + for signaling: Bool in Bool.all { + result.append( Float64(nan: nan, signaling: signaling)) + result.append(-Float64(nan: nan, signaling: signaling)) + } } + return result + }() + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + @Test( + "BinaryInteger/floats/samples: none", + arguments: Self.nonresults + ) func nonresults(float: Float64) throws { for source in typesAsSwiftBinaryFloatingPoint { for destination in typesAsBinaryInteger { - whereIs(source: source, destination: destination) + try whereIs(source: source, destination: destination) + } + } + + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: BinaryInteger { + if let source = A(exactly: float) { + try Ɣrequire(source,is: Optional>.none) } } } - func testInitFloatInfinityIsNil() { - func whereIs(source: A.Type, destination: B.Type) where A: Swift.BinaryFloatingPoint, B: BinaryInteger { - Test().stdlib( A.infinity, is: Optional.none) - Test().stdlib(-A.infinity, is: Optional.none) - } - + @Test( + "BinaryInteger/floats/samples: integers", + arguments: Self.integers + ) func integers(float: Float64, integer: IXL) throws { for source in typesAsSwiftBinaryFloatingPoint { for destination in typesAsBinaryInteger { - whereIs(source: source, destination: destination) + try whereIs(source: source, destination: destination) + } + } + + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: BinaryInteger { + if let source = A(exactly: float) { + try Ɣrequire(source,is: integer.veto(false), as: B.self) } } } - func testInitFloatPureExponent() { - func whereIs(source: A.Type, destination: B.Type) where A: Swift.BinaryFloatingPoint, B: BinaryInteger { - let size = IX(size: B.self) ?? 128 - for exponent: IX in 0 ..< 2 * size { - //=------------------------------= - let positive = Double(sign: .plus, exponent: Int(exponent), significand: 1) - let negative = Double(sign: .minus, exponent: Int(exponent), significand: 1) - //=------------------------------= - if let distance = Shift(exactly: Count(exponent)) { - let magnitude = B.Magnitude.lsb.up(distance) - Test().stdlib(positive, is: B.exactly(sign: .plus, magnitude: magnitude).optional(), exactly: true) - Test().stdlib(negative, is: B.exactly(sign: .minus, magnitude: magnitude).optional(), exactly: true) - } else { - Test().stdlib(positive, is: Optional.none) - Test().stdlib(negative, is: Optional.none) - } + @Test( + "BinaryInteger/floats/samples: integers but one fractional step away from zero", + arguments: Self.integersButOneFractionalStepAwayFromZero + ) func integersButOneFractionalStepAwayFromZero(float: Float64, integer: Fallible) throws { + for source in typesAsSwiftBinaryFloatingPoint { + for destination in typesAsBinaryInteger { + try whereIs(source: source, destination: destination) } } + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: BinaryInteger { + if let source = A(exactly: float) { + try Ɣrequire(source,is: integer, as: B.self) + } + } + } + + @Test( + "BinaryInteger/floats/samples: integers but one fractional step towards zero", + arguments: Self.integersButOneFractionalStepTowardsZero + ) func integersButOneFractionalStepTowardsZero(float: Float64, integer: Fallible) throws { for source in typesAsSwiftBinaryFloatingPoint { for destination in typesAsBinaryInteger { - whereIs(source: source, destination: destination) + try whereIs(source: source, destination: destination) + } + } + + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: BinaryInteger { + if let source = A(exactly: float) { + try Ɣrequire(source,is: integer, as: B.self) } } } //=------------------------------------------------------------------------= - // MARK: Tests + // MARK: Utilities //=------------------------------------------------------------------------= - func testInitGreatestFiniteMagnitudeAsFloat32() { - let positive = IXL(340282346638528859811704183484516925440) - let negative = positive.negated().unwrap() + private func Ɣrequire( + _ source: A, + is destination: Fallible, + as type: B.Type, + at location: SourceLocation = #_sourceLocation + ) throws where A: Swift.BinaryFloatingPoint, B: BinaryInteger { - func whereIs(_ type: T.Type) where T: BinaryInteger { - Test().stdlib( Float32.greatestFiniteMagnitude, is: T.exactly(positive).optional(), exactly: true) - Test().stdlib(-Float32.greatestFiniteMagnitude, is: T.exactly(negative).optional(), exactly: true) - } + let expectation: B? = B.exactly(destination.value).optional() + try Ɣrequire(source, is: expectation?.veto(destination.error)) + } + + private func Ɣrequire( + _ source: A, + is destination: Optional>, + at location: SourceLocation = #_sourceLocation + ) throws where A: Swift.BinaryFloatingPoint, B: BinaryInteger { - for type in typesAsBinaryInteger { - whereIs(type) + if let destination { + try #require(B.init (source) == destination.value, sourceLocation: location) + try #require(B.exactly (source) == destination.optional(), sourceLocation: location) + try #require(B.leniently(source) == destination, sourceLocation: location) + } else { + try #require(B.exactly (source) == nil, sourceLocation: location) + try #require(B.leniently(source) == nil, sourceLocation: location) } } +} + +//*============================================================================* +// MARK: * Binary Integer x Floats x Generators +//*============================================================================* + +@Suite struct BinaryIntegerTestsOnFloatsGenerators { - func testInitGreatestFiniteMagnitudeAsFloat64() { - let positive = IXL(""" - 0000000000017976931348623157081452742373170435679807056752584499\ - 6598917476803157260780028538760589558632766878171540458953514382\ - 4642343213268894641827684675467035375169860499105765512820762454\ - 9009038932894407586850845513394230458323690322294816580855933212\ - 3348274797826204144723168738177180919299881250404026184124858368 - """)! - let negative = positive.negated().unwrap() - - func whereIs(_ type: T.Type) where T: BinaryInteger { - Test().stdlib( Float64.greatestFiniteMagnitude, is: T.exactly(positive).optional(), exactly: true) - Test().stdlib(-Float64.greatestFiniteMagnitude, is: T.exactly(negative).optional(), exactly: true) + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + @Test func fromPureExponentFloats() throws { + for source in typesAsSwiftBinaryFloatingPoint { + for destination in typesAsBinaryInteger { + try whereIs(source: source, destination: destination) + } } - for type in typesAsBinaryInteger { - whereIs(type) + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: BinaryInteger { + try withOnlyOneCallToRequire((source, destination)) { require in + let size = IX(size: B.self) ?? 128 + + for exponent: IX in -(2 * size) ..< (2 * size) { + let positive = Double(sign: .plus, exponent: Int(exponent), significand: 1) + let negative = Double(sign: .minus, exponent: Int(exponent), significand: 1) + + if exponent.isNegative { + require(B.leniently(positive) == B.zero.veto()) + require(B.leniently(negative) == B.zero.veto()) + + } else if let distance = Shift(exactly: Count(exponent)) { + let magnitude = B.Magnitude.lsb.up(distance) + require(B.exactly (positive) == B.exactly(sign: Sign.plus, magnitude: magnitude).optional()) + require(B.exactly (negative) == B.exactly(sign: Sign.minus, magnitude: magnitude).optional()) + + } else { + require(B.leniently(positive) == nil) + require(B.leniently(negative) == nil) + } + } + } } } @@ -179,34 +281,41 @@ final class BinaryIntegerTestsOnFloats: XCTestCase { /// 1111111111111111111111111111111111111111111111111110110011000011 → /// 1111111111111111111111111111111111111111111111111111110011000011 → /// - func testInitLargeNegativeFloats() { - func whereIs( - source: A.Type, destination: B.Type, exponents: IX, steps: IX - ) where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { + @Test func fromLargeNegativeFloats() throws { + for source in typesAsSwiftBinaryFloatingPoint { + try whereIs(source: source, destination: InfiniInt.self) + try whereIs(source: source, destination: InfiniInt.self) + } + + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { //=----------------------------------= let start = A.significandBitCount + let end = A.significandBitCount + 32 + let steps = A.significandBitCount //=----------------------------------= - for exponent in start ..< start + Swift.Int(exponents) { - var source = A(sign: .minus, exponent: A.Exponent(exponent), significand: 1) - var sourceStep: A = source.ulp - var destination = B.isSigned ? B(-1) << IX(exponent) : nil - var destinationStep = B.exactly(sourceStep)! - - for _ in 0 ..< steps { - source -= sourceStep - sourceStep += sourceStep - destination? -= destinationStep - destinationStep += destinationStep - Test().stdlib(source, is: destination, exactly: true) + for exponent in start ..< end { + try withOnlyOneCallToRequire((source, destination)) { require in + var source = A.init( + sign: FloatingPointSign.minus, + exponent: A.Exponent(exponent), + significand: 1.0 as A + ) + + var sourceStep: A = source.ulp + var destination = B.isSigned ? B(-1) << IX(exponent) : nil + var destinationStep = B.exactly(sourceStep)! + + for _ in 0 ..< steps { + source -= sourceStep + sourceStep += sourceStep + destination? -= destinationStep + destinationStep += destinationStep + require(destination == B.exactly(source)) + } } } } - - for source in typesAsSwiftBinaryFloatingPoint { - let steps = IX(source.significandBitCount) - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: steps) - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: steps) - } } /// Checks some bit patterns for exponents >= 52 (64-bit). @@ -221,32 +330,40 @@ final class BinaryIntegerTestsOnFloats: XCTestCase { /// 0110000000000000000000000000000000000000000000000000110011000011 → /// 1110000000000000000000000000000000000000000000000000110011000011 → /// - func testInitLargeNegativeFloatsNearMinSignificandBitPattern() { - func whereIs( - source: A.Type, destination: B.Type, exponents: IX, steps: IX - ) where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { + @Test func fromLargeNegativeFloatsNearMinSignificandBitPattern() throws { + for source in typesAsSwiftBinaryFloatingPoint { + try whereIs(source: source, destination: InfiniInt.self) + try whereIs(source: source, destination: InfiniInt.self) + } + + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { //=----------------------------------= let start = A.significandBitCount - Test().same(A(sign: .minus, exponent: A.Exponent(start), significand: 1).ulp, 1) + let end = A.significandBitCount + 32 + let steps = 32 + try #require(1 == A(sign: .minus, exponent: A.Exponent(start), significand: 1).ulp) //=----------------------------------= - for exponent in start ..< start + Swift.Int(exponents) { - var source = A(sign: .minus, exponent: A.Exponent(exponent), significand: 1) - let sourceStep: A = source.ulp - var destination = B.isSigned ? B(-1) << IX(exponent) : nil - let destinationStep = B.exactly(sourceStep)! - - for _ in 0 ..< steps { - Test().stdlib(source, is: destination, exactly: true) - source -= sourceStep - destination? -= destinationStep + for exponent in start ..< end { + try withOnlyOneCallToRequire((source, destination)) { require in + var source = A.init( + sign: FloatingPointSign.minus, + exponent: A.Exponent(exponent), + significand: 1.0 as A + ) + + let sourceStep: A = source.ulp + var destination = B.isSigned ? B(-1) << IX(exponent) : nil + let destinationStep = B.exactly(sourceStep)! + + for _ in 0 ..< steps { + require(destination == B.exactly(source)) + source -= sourceStep + destination? -= destinationStep + } } } } - - for source in typesAsSwiftBinaryFloatingPoint { - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: 32) - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: 32) - } } /// Checks some bit patterns for exponents >= 52 (64-bit). @@ -261,33 +378,41 @@ final class BinaryIntegerTestsOnFloats: XCTestCase { /// 1001111111111111111111111111111111111111111111111111110011000011 → /// 0001111111111111111111111111111111111111111111111111110011000011 → /// - func testInitLargeNegativeFloatsNearMaxSignificandBitPattern() { - func whereIs( - source: A.Type, destination: B.Type, exponents: IX, steps: IX - ) where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { + @Test func fromLargeNegativeFloatsNearMaxSignificandBitPattern() throws { + for source in typesAsSwiftBinaryFloatingPoint { + try whereIs(source: source, destination: InfiniInt.self) + try whereIs(source: source, destination: InfiniInt.self) + } + + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { //=----------------------------------= let start = A.significandBitCount + 1 - Test().same(A(sign: .minus, exponent: A.Exponent(start), significand: 1).ulp, 2) - Test().same(A(sign: .minus, exponent: A.Exponent(start), significand: 1).nextUp.ulp, 1) + let end = A.significandBitCount + 1 + 32 + let steps = 32 + try #require(2 == A(sign: .minus, exponent: A.Exponent(start), significand: 1).ulp) + try #require(1 == A(sign: .minus, exponent: A.Exponent(start), significand: 1).nextUp.ulp) //=----------------------------------= - for exponent in start ..< start + Swift.Int(exponents) { - var source = A(sign: .minus, exponent: A.Exponent(exponent), significand: 1) - let sourceStep: A = source.nextUp.ulp - var destination = B.isSigned ? B(-1) << IX(exponent) : nil - let destinationStep = B.exactly(sourceStep)! - - for _ in 0 ..< steps { - source += sourceStep - destination? += destinationStep - Test().stdlib(source, is: destination, exactly: true) + for exponent in start ..< end { + try withOnlyOneCallToRequire((source, destination)) { require in + var source = A.init( + sign: FloatingPointSign.minus, + exponent: A.Exponent(exponent), + significand: 1.0 as A + ) + + let sourceStep: A = source.nextUp.ulp + var destination = B.isSigned ? B(-1) << IX(exponent) : nil + let destinationStep = B.exactly(sourceStep)! + + for _ in 0 ..< steps { + source += sourceStep + destination? += destinationStep + require(destination == B.exactly(source)) + } } } } - - for source in typesAsSwiftBinaryFloatingPoint { - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: 32) - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: 32) - } } /// Checks some bit patterns for exponents >= 52 (64-bit). @@ -302,34 +427,41 @@ final class BinaryIntegerTestsOnFloats: XCTestCase { /// 1111111111111111111111111111111111111111111111111110110011000010 → /// 1111111111111111111111111111111111111111111111111111110011000010 → /// - func testInitLargePositiveFloats() { - func whereIs( - source: A.Type, destination: B.Type, exponents: IX, steps: IX - ) where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { + @Test func fromLargePositiveFloats() throws { + for source in typesAsSwiftBinaryFloatingPoint { + try whereIs(source: source, destination: InfiniInt.self) + try whereIs(source: source, destination: InfiniInt.self) + } + + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { //=----------------------------------= let start = A.significandBitCount + let end = A.significandBitCount + 32 + let steps = A.significandBitCount //=----------------------------------= - for exponent in start ..< start + Swift.Int(exponents) { - var source = A(sign: .plus, exponent: A.Exponent(exponent), significand: 1) - var sourceStep: A = source.ulp - var destination = B.lsb << IX(exponent) - var destinationStep = B.exactly(sourceStep)! - - for _ in 0 ..< steps { - source += sourceStep - sourceStep += sourceStep - destination += destinationStep - destinationStep += destinationStep - Test().stdlib(source, is: destination, exactly: true) + for exponent in start ..< end { + try withOnlyOneCallToRequire((source, destination)) { require in + var source = A.init( + sign: FloatingPointSign.plus, + exponent: A.Exponent(exponent), + significand: 1.0 as A + ) + + var sourceStep: A = source.ulp + var destination = B.lsb << IX(exponent) + var destinationStep = B.exactly(sourceStep)! + + for _ in 0 ..< steps { + source += sourceStep + sourceStep += sourceStep + destination += destinationStep + destinationStep += destinationStep + require(destination == B.exactly(source)) + } } } } - - for source in typesAsSwiftBinaryFloatingPoint { - let steps = IX(source.significandBitCount) - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: steps) - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: steps) - } } /// Checks some bit patterns for exponents >= 52 (64-bit). @@ -344,32 +476,40 @@ final class BinaryIntegerTestsOnFloats: XCTestCase { /// 0110000000000000000000000000000000000000000000000000110011000010 → /// 1110000000000000000000000000000000000000000000000000110011000010 → /// - func testInitLargePositiveFloatsNearMinSignificandBitPattern() { - func whereIs( - source: A.Type, destination: B.Type, exponents: IX, steps: IX - ) where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { + @Test func fromLargePositiveFloatsNearMinSignificandBitPattern() throws { + for source in typesAsSwiftBinaryFloatingPoint { + try whereIs(source: source, destination: InfiniInt.self) + try whereIs(source: source, destination: InfiniInt.self) + } + + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { //=----------------------------------= let start = A.significandBitCount - Test().same(A(sign: .plus, exponent: A.Exponent(start), significand: 1).ulp, 1) + let end = A.significandBitCount + 32 + let steps = 32 + try #require(1 == A(sign: .plus, exponent: A.Exponent(start), significand: 1).ulp) //=----------------------------------= - for exponent in start ..< start + Swift.Int(exponents) { - var source = A(sign: .plus, exponent: A.Exponent(exponent), significand: 1) - let sourceStep: A = source.ulp - var destination = B.lsb << exponent - let destinationStep = B.exactly(sourceStep)! - - for _ in 0 ..< steps { - Test().stdlib(source, is: destination, exactly: true) - source += sourceStep - destination += destinationStep + for exponent in start ..< end { + try withOnlyOneCallToRequire((source, destination)) { require in + var source = A.init( + sign: FloatingPointSign.plus, + exponent: A.Exponent(exponent), + significand: 1.0 as A + ) + + let sourceStep: A = source.ulp + var destination = B.lsb << exponent + let destinationStep = B.exactly(sourceStep)! + + for _ in 0 ..< steps { + require(destination == B.exactly(source)) + source += sourceStep + destination += destinationStep + } } } } - - for source in typesAsSwiftBinaryFloatingPoint { - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: 32) - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: 32) - } } /// Checks some bit patterns for exponents >= 52 (64-bit). @@ -384,32 +524,35 @@ final class BinaryIntegerTestsOnFloats: XCTestCase { /// 1001111111111111111111111111111111111111111111111111110011000010 → /// 0001111111111111111111111111111111111111111111111111110011000010 → /// - func testInitLargePositiveFloatsNearMaxSignificandBitPattern() { - func whereIs( - source: A.Type, destination: B.Type, exponents: IX, steps: IX - ) where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { + @Test func fromLargePositiveFloatsNearMaxSignificandBitPattern() throws { + for source in typesAsSwiftBinaryFloatingPoint { + try whereIs(source: source, destination: InfiniInt.self) + try whereIs(source: source, destination: InfiniInt.self) + } + + func whereIs(source: A.Type, destination: B.Type) throws + where A: Swift.BinaryFloatingPoint, B: ArbitraryInteger { //=----------------------------------= let start = A.significandBitCount + 1 - Test().same(A(sign: .plus, exponent: A.Exponent(start), significand: 1).ulp, 2) - Test().same(A(sign: .plus, exponent: A.Exponent(start), significand: 1).nextDown.ulp, 1) + let end = A.significandBitCount + 1 + 32 + let steps = 32 + try #require(2 == A(sign: .plus, exponent: A.Exponent(start), significand: 1).ulp) + try #require(1 == A(sign: .plus, exponent: A.Exponent(start), significand: 1).nextDown.ulp) //=----------------------------------= - for exponent in start ..< start + Swift.Int(exponents) { - var source = A(sign: .plus, exponent: A.Exponent(exponent), significand: 1) - let sourceStep: A = source.nextDown.ulp - var destination = B.lsb << IX(exponent) - let destinationStep = B.exactly(sourceStep)! - - for _ in 0 ..< steps { - source -= sourceStep - destination -= destinationStep - Test().stdlib(source, is: destination, exactly: true) + for exponent in start ..< end { + try withOnlyOneCallToRequire((source, destination)) { require in + var source = A(sign: .plus, exponent: A.Exponent(exponent), significand: 1) + let sourceStep: A = source.nextDown.ulp + var destination = B.lsb << IX(exponent) + let destinationStep = B.exactly(sourceStep)! + + for _ in 0 ..< steps { + source -= sourceStep + destination -= destinationStep + require(destination == B.exactly(source)) + } } } } - - for source in typesAsSwiftBinaryFloatingPoint { - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: 32) - whereIs(source: source, destination: InfiniInt.self, exponents: 32, steps: 32) - } } }