Skip to content

[stdlib] Better testing for floating point types #2883

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 4, 2016
7 changes: 7 additions & 0 deletions stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ public func expectEqual<T : Equatable, U : Equatable>(
expectEqual(expected.1, actual.1, ${trace}, showFrame: false) {$0 == $1}
}

public func expectEqual<T : Equatable, U : Equatable, V : Equatable>(
_ expected: (T, U, V), _ actual: (T, U, V), ${TRACE}) {
expectEqual(expected.0, actual.0, ${trace}, showFrame: false) {$0 == $1}
expectEqual(expected.1, actual.1, ${trace}, showFrame: false) {$0 == $1}
expectEqual(expected.2, actual.2, ${trace}, showFrame: false) {$0 == $1}
}

public func expectationFailure(
_ reason: String,
trace message: String,
Expand Down
2 changes: 0 additions & 2 deletions stdlib/public/core/FloatingPointTypes.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ builtinIntLiteralBits = 2048
# Mapping from float bits to significand bits
explicitSignificandBits = { 32:24, 64:53, 80:64 }

cFunctionSuffix = { 32:'f', 64:'', 80:'l' }

def allInts():
for bits in allIntBits:
for signed in False, True:
Expand Down
148 changes: 130 additions & 18 deletions test/1_stdlib/FloatingPoint.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
// RUN: %S/../../utils/line-directive %t/FloatingPoint.swift -- %target-run %t/a.out
// REQUIRES: executable_test

%{
from gyb_stdlib_unittest_support import TRACE, stackTrace, trace
}%

import Swift
import StdlibUnittest


#if arch(i386) || arch(x86_64)

struct Float80Bits : Equatable, CustomStringConvertible {
Expand All @@ -19,7 +22,7 @@ struct Float80Bits : Equatable, CustomStringConvertible {
}

var description: String {
return "(\(String(signAndExponent, radix: 16)) \(String(significand, radix: 16))))"
return "(\(String(signAndExponent, radix: 16)) \(String(significand, radix: 16)))"
}
}

Expand Down Expand Up @@ -51,6 +54,29 @@ extension Float80 {

#endif

% for (FloatTy, BitPatternTy) in [
% ('Float', 'UInt32'),
% ('Double', 'UInt64'),
% ('Float80', 'Float80Bits')
% ]:
% if FloatTy == 'Float80':
#if arch(i386) || arch(x86_64)
% end
func expectBitwiseEqual(
_ expected: ${FloatTy}, _ actual: ${FloatTy}, ${TRACE}
) {
expectEqual(expected.bitPattern, actual.bitPattern, ${trace})
}
func expectBitwiseEqual(
bitPattern expected: ${BitPatternTy}, _ actual: ${FloatTy}, ${TRACE}
) {
expectBitwiseEqual(${FloatTy}(bitPattern: expected), actual, ${trace})
}
% if FloatTy == 'Float80':
#endif
% end
% end

var FloatingPoint = TestSuite("FloatingPoint")

func positiveOne<T: IntegerLiteralConvertible>() -> T {
Expand All @@ -65,6 +91,29 @@ FloatingPoint.test("Float/IntegerLiteralConvertible") {
expectEqual(negativeOne(), -1.0 as Float)
}

FloatingPoint.test("Float/FloatLiteralConvertible") {
let x: Float = -0.0
expectBitwiseEqual(bitPattern: 0x8000_0000, x)
}

FloatingPoint.test("Float/staticProperties") {
typealias Ty = Float
// From the FloatingPoint protocol.
expectEqual(2, Ty.radix)
expectBitwiseEqual(bitPattern: 0x7fc0_0000, Ty.nan)
expectBitwiseEqual(bitPattern: 0x7fa0_0000, Ty.signalingNaN)
expectBitwiseEqual(bitPattern: 0x7f80_0000, Ty.infinity)
expectBitwiseEqual(0x1.ffff_fe__p127, Ty.greatestFiniteMagnitude)
expectBitwiseEqual(0x1.921f_b6__p1, Ty.pi)
expectBitwiseEqual(0x1.0p-23, Ty.ulpOfOne)
expectBitwiseEqual(0x1.0p-126, Ty.leastNormalMagnitude)
expectBitwiseEqual(0x1.0p-149, Ty.leastNonzeroMagnitude)

// From the BinaryFloatingPoint protocol.
expectEqual(8, Ty.exponentBitCount)
expectEqual(23, Ty.significandBitCount)
}

// Tests the float and int conversions work correctly. Each case is special.
FloatingPoint.test("Float/UInt8") {
expectEqual(UInt8.min, UInt8(Float(UInt8.min)))
Expand Down Expand Up @@ -115,6 +164,29 @@ FloatingPoint.test("Double/IntegerLiteralConvertible") {
expectEqual(negativeOne(), -1.0 as Double)
}

FloatingPoint.test("Double/FloatLiteralConvertible") {
let x: Double = -0.0
expectBitwiseEqual(bitPattern: 0x8000_0000_0000_0000, x)
}

FloatingPoint.test("Double/staticProperties") {
typealias Ty = Double
// From the FloatingPoint protocol.
expectEqual(2, Ty.radix)
expectBitwiseEqual(bitPattern: 0x7ff8_0000_0000_0000, Ty.nan)
expectBitwiseEqual(bitPattern: 0x7ff4_0000_0000_0000, Ty.signalingNaN)
expectBitwiseEqual(bitPattern: 0x7ff0_0000_0000_0000, Ty.infinity)
expectBitwiseEqual(0x1.ffff_ffff_ffff_f__p1023, Ty.greatestFiniteMagnitude)
expectBitwiseEqual(0x1.921f_b544_42d1_8__p1, Ty.pi)
expectBitwiseEqual(0x1.0p-52, Ty.ulpOfOne)
expectBitwiseEqual(0x1.0p-1022, Ty.leastNormalMagnitude)
expectBitwiseEqual(0x1.0p-1074, Ty.leastNonzeroMagnitude)

// From the BinaryFloatingPoint protocol.
expectEqual(11, Ty.exponentBitCount)
expectEqual(52, Ty.significandBitCount)
}

FloatingPoint.test("Double/UInt8") {
expectEqual(UInt8.min, UInt8(Double(UInt8.min)))
expectEqual(UInt8.max, UInt8(Double(UInt8.max)))
Expand Down Expand Up @@ -174,37 +246,35 @@ FloatingPoint.test("Double/HashValueZero") {
let floatNextUpDownTests: [(Float, Float)] = [
(.nan, .nan),
(.greatestFiniteMagnitude, .infinity),
(-.infinity, -.greatestFiniteMagnitude),
(0x1.fffffep-1, 1.0), (1.0, 0x1.000002p+0),
(-0x1p-149, -0.0), (0.0, 0x1p-149),
(0x1.effffep-1, 0.96875), (0.96875, 0x1.f00002p-1),
(0x1.ffff_fe__p-1, 1.0), (1.0, 0x1.0000_02__p+0),
(0.0, .leastNonzeroMagnitude),
(0x1.efff_fe__p-1, 0x1.fp-1), (0x1.fp-1, 0x1.f000_02__p-1),
]

FloatingPoint.test("Float.nextUp, .nextDown")
.forEach(in: floatNextUpDownTests) {
(prev, succ) in
expectEqual(succ.bitPattern, prev.nextUp.bitPattern)
expectEqual(prev.bitPattern, succ.nextDown.bitPattern)
expectEqual((-succ).bitPattern, (-prev).nextDown.bitPattern)
expectEqual((-prev).bitPattern, (-succ).nextUp.bitPattern)
expectBitwiseEqual(succ, prev.nextUp)
expectBitwiseEqual(prev, succ.nextDown)
expectBitwiseEqual(-succ, (-prev).nextDown)
expectBitwiseEqual(-prev, (-succ).nextUp)
}

let doubleNextUpDownTests: [(Double, Double)] = [
(.nan, .nan),
(.greatestFiniteMagnitude, .infinity),
(-.infinity, -.greatestFiniteMagnitude),
(0x1.fffffffffffffp-1, 1.0), (1.0, 0x1.0000000000001p+0),
(-0x1p-1074, -0.0), (0.0, 0x1p-1074),
(0x1.effffffffffffp-1, 0.96875), (0.96875, 0x1.f000000000001p-1),
(0x1.ffff_ffff_ffff_fp-1, 1.0), (1.0, 0x1.0000_0000_0000_1p+0),
(0.0, .leastNonzeroMagnitude),
(0x1.efff_ffff_ffff_fp-1, 0x1.fp-1), (0x1.fp-1, 0x1.f000_0000_0000_1p-1),
]

FloatingPoint.test("Double.nextUp, .nextDown")
.forEach(in: doubleNextUpDownTests) {
(prev, succ) in
expectEqual(succ.bitPattern, prev.nextUp.bitPattern)
expectEqual(prev.bitPattern, succ.nextDown.bitPattern)
expectEqual((-succ).bitPattern, (-prev).nextDown.bitPattern)
expectEqual((-prev).bitPattern, (-succ).nextUp.bitPattern)
expectBitwiseEqual(succ, prev.nextUp)
expectBitwiseEqual(prev, succ.nextDown)
expectBitwiseEqual(-succ, (-prev).nextDown)
expectBitwiseEqual(-prev, (-succ).nextUp)
}

#if arch(i386) || arch(x86_64)
Expand All @@ -214,13 +284,55 @@ FloatingPoint.test("Float80/IntegerLiteralConvertible") {
expectEqual(negativeOne(), -1.0 as Float80)
}

FloatingPoint.test("Float80/FloatLiteralConvertible") {
let x: Float80 = -0.0
expectBitwiseEqual(bitPattern: Float80Bits(0x8000, 0), x)
}

FloatingPoint.test("Float80/staticProperties") {
typealias Ty = Double
// From the FloatingPoint protocol.
expectEqual(2, Ty.radix)
expectBitwiseEqual(bitPattern: 0x7ff8_0000_0000_0000, Ty.nan)
expectBitwiseEqual(bitPattern: 0x7ff4_0000_0000_0000, Ty.signalingNaN)
expectBitwiseEqual(bitPattern: 0x7ff0_0000_0000_0000, Ty.infinity)
expectBitwiseEqual(0x1.ffff_ffff_ffff_f__p1023, Ty.greatestFiniteMagnitude)
expectBitwiseEqual(0x1.921f_b544_42d1_8__p1, Ty.pi)
expectBitwiseEqual(0x1.0p-52, Ty.ulpOfOne)
expectBitwiseEqual(0x1.0p-1022, Ty.leastNormalMagnitude)
expectBitwiseEqual(0x1.0p-1074, Ty.leastNonzeroMagnitude)

// From the BinaryFloatingPoint protocol.
expectEqual(11, Ty.exponentBitCount)
expectEqual(52, Ty.significandBitCount)
}

FloatingPoint.test("Float80/HashValueZero") {
let zero: Float80 = getFloat80(0.0)
let negativeZero: Float80 = getFloat80(-0.0)
expectNotEqual(zero.bitPattern, negativeZero.bitPattern)
expectEqual(zero.hashValue, negativeZero.hashValue)
}

let float80NextUpDownTests: [(Float80, Float80)] = [
(.nan, .nan),
(.greatestFiniteMagnitude, .infinity),
(0x1.ffff_ffff_ffff_fffep-1, 1.0), (1.0, 0x1.0000_0000_0000_0002p+0),
(0.0, .leastNonzeroMagnitude),
(0x1.efff_ffff_ffff_fffep-1, 0x1.fp-1),
(0x1.fp-1, 0x1.f000_0000_0000_0002p-1),
]

FloatingPoint.test("Float80.nextUp, .nextDown")
.forEach(in: float80NextUpDownTests) {
(prev, succ) in

expectBitwiseEqual(succ, prev.nextUp)
expectBitwiseEqual(prev, succ.nextDown)
expectBitwiseEqual(-succ, (-prev).nextDown)
expectBitwiseEqual(-prev, (-succ).nextUp)
}

#endif

% for FloatSelf in ['Float32', 'Float64']:
Expand Down
62 changes: 62 additions & 0 deletions validation-test/StdlibUnittest/Assertions.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -162,5 +162,67 @@ AssertionsTestSuite.test("expectEqualsUnordered(Range<T>, [T])") {
% end
}

AssertionsTestSuite.test("expectEqual<T : Equatable>") {
let _0 = MinimalEquatableValue(0)
let _1 = MinimalEquatableValue(1)

expectEqual(_0, _0)
expectEqual(_1, _1)
expectFailure {
expectEqual(_0, _1)
expectEqual(_1, _0)
}
}

AssertionsTestSuite.test("expectEqual<T : Equatable, U : Equatable>") {
let _0 = MinimalEquatableValue(0)
let _1 = MinimalEquatableValue(1)

for a in [_0, _1] {
for b in [_0, _1] {
for c in [_0, _1] {
for d in [_0, _1] {
let lhs = (a, b)
let rhs = (c, d)
if lhs == rhs {
expectEqual(lhs, rhs)
} else {
expectFailure {
expectEqual(lhs, rhs)
}
}
}
}
}
}
}

AssertionsTestSuite.test("expectEqual<T : Equatable, U : Equatable, V : Equatable>") {
let _0 = MinimalEquatableValue(0)
let _1 = MinimalEquatableValue(1)

for a in [_0, _1] {
for b in [_0, _1] {
for c in [_0, _1] {
for d in [_0, _1] {
for e in [_0, _1] {
for f in [_0, _1] {
let lhs = (a, b, c)
let rhs = (d, e, f)
if lhs == rhs {
expectEqual(lhs, rhs)
} else {
expectFailure {
expectEqual(lhs, rhs)
}
}
}
}
}
}
}
}
}

runAllTests()