// RUN: %target-run-simple-swiftgyb(-parse-stdlib)
// REQUIRES: executable_test

// rdar://104232602
// UNSUPPORTED: CPU=x86_64 && (DARWIN_SIMULATOR=ios || DARWIN_SIMULATOR=watchos || DARWIN_SIMULATOR=tvos)

import Swift
import StdlibUnittest

#if !os(Windows) && (arch(i386) || arch(x86_64))

struct Float80Bits : Equatable, CustomStringConvertible {
  var signAndExponent: UInt16
  var significand: UInt64

  init(_ signAndExponent: UInt16, _ significand: UInt64) {
    self.signAndExponent = signAndExponent
    self.significand = significand
  }

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

func == (lhs: Float80Bits, rhs: Float80Bits) -> Bool {
  return
    lhs.signAndExponent == rhs.signAndExponent &&
    lhs.significand == rhs.significand
}

extension Float80 {
  var bitPattern: Float80Bits {
    let bits = Builtin.bitcast_FPIEEE80_Int80(self._value)
    let sixtyFour = Builtin.zextOrBitCast_Int64_Int80((64 as Int64)._value)
    return Float80Bits(
      UInt16(Builtin.truncOrBitCast_Int80_Int16(
        Builtin.lshr_Int80(bits, sixtyFour))),
      UInt64(Builtin.truncOrBitCast_Int80_Int64(bits)))
  }

  init(bitPattern: Float80Bits) {
    var result = Builtin.shl_Int80(
      Builtin.zextOrBitCast_Int16_Int80(bitPattern.signAndExponent._value),
      Builtin.zextOrBitCast_Int64_Int80((64 as Int64)._value))
    result = Builtin.or_Int80(
      result, Builtin.zextOrBitCast_Int64_Int80(bitPattern.significand._value))
    self = Float80(Builtin.bitcast_Int80_FPIEEE80(result))
  }
}

#endif

% for (FloatTy, BitPatternTy) in [
%   ('Float', 'UInt32'),
%   ('Double', 'UInt64'),
%   ('Float80', 'Float80Bits')
% ]:
%   if FloatTy == 'Float80':
#if !os(Windows) && (arch(i386) || arch(x86_64))
%   end
func expectBitwiseEqual(
  _ expected: ${FloatTy}, _ actual: ${FloatTy},
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  expectEqual(expected.bitPattern, actual.bitPattern, message(),
  stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
}
func expectBitwiseEqual(
  bitPattern expected: ${BitPatternTy}, _ actual: ${FloatTy},
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  expectBitwiseEqual(${FloatTy}(bitPattern: expected), actual, message(),
  stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
}
%   if FloatTy == 'Float80':
#endif
%   end
% end

var FloatingPoint = TestSuite("FloatingPoint")

FloatingPoint.test("BinaryFloatingPoint/genericIntegerConversion") {
  expectTrue(Double._convert(from: 0) == (value: 0, exact: true))

  expectTrue(Double._convert(from: 1) == (value: 1, exact: true))
  expectTrue(Double._convert(from: -1) == (value: -1, exact: true))

  expectTrue(Double._convert(from: 42) == (value: 42, exact: true))
  expectTrue(Double._convert(from: -42) == (value: -42, exact: true))

  expectTrue(Double._convert(from: 100) == (value: 100, exact: true))
  expectTrue(Double._convert(from: -100) == (value: -100, exact: true))

  expectEqual(Double._convert(from: Int64.max).value, Double(Int64.max))
  expectEqual(Double._convert(from: Int64.min).value, Double(Int64.min))

  var x = ((Int64.max >> 11) + 1) << 11
  expectEqual(Double._convert(from: x).value, Double(x))
  x = (Int64.max >> 12) << 12 + 1
  expectEqual(Double._convert(from: x).value, Double(x))
  x = Int64.min + 1
  expectEqual(Double._convert(from: x).value, Double(x))

  expectEqual(Float._convert(from: Int64.max).value, Float(Int64.max))
  expectEqual(Float._convert(from: Int64.min).value, Float(Int64.min))

}

FloatingPoint.test("BinaryFloatingPoint/genericFloatingPointConversion") {
  func convert<
    T: BinaryFloatingPoint, U: BinaryFloatingPoint
  >(exactly value: T, to: U.Type) -> U? { U(exactly: value) }
  
  expectEqual(convert(exactly: 0 as Float, to: Double.self), 0.0)
  expectEqual(convert(exactly: -0.0 as Float, to: Double.self), -0.0)
  expectEqual(
    convert(exactly: -0.0 as Float, to: Double.self)?.sign,
    FloatingPointSign.minus)
  expectEqual(convert(exactly: 0 as Double, to: Float.self), 0.0 as Float)
  expectEqual(convert(exactly: -0.0 as Double, to: Float.self), -0.0 as Float)
  expectEqual(
    convert(exactly: -0.0 as Double, to: Float.self)?.sign,
    FloatingPointSign.minus)
  expectEqual(convert(exactly: 1 as Float, to: Double.self), 1.0)
  expectEqual(convert(exactly: -1 as Float, to: Double.self), -1.0)
  expectEqual(convert(exactly: 1 as Double, to: Float.self), 1.0 as Float)
  expectEqual(convert(exactly: -1 as Double, to: Float.self), -1.0 as Float)
  expectEqual(
    convert(exactly: Float.infinity, to: Double.self), Double.infinity)
  expectEqual(
    convert(exactly: -Float.infinity, to: Double.self), -Double.infinity)
  expectEqual(
    convert(exactly: Double.infinity, to: Float.self), Float.infinity)
  expectEqual(
    convert(exactly: -Double.infinity, to: Float.self), -Float.infinity)
  expectEqual(convert(exactly: Float.nan, to: Double.self), nil)
  expectEqual(convert(exactly: Double.nan, to: Float.self), nil)
  expectEqual(convert(exactly: Float.nan, to: Float.self), nil)
  expectEqual(convert(exactly: Double.nan, to: Double.self), nil)
  expectEqual(
    convert(exactly: Double.leastNonzeroMagnitude, to: Float.self), nil)
  expectEqual(
    convert(exactly: Float.leastNonzeroMagnitude, to: Double.self),
    Double(Float.leastNonzeroMagnitude))
  expectEqual(
    convert(exactly: Double.greatestFiniteMagnitude, to: Float.self), nil)
  expectEqual(
    convert(exactly: Float.greatestFiniteMagnitude, to: Double.self),
    Double(Float.greatestFiniteMagnitude))
  
  expectTrue(Double._convert(from: 0 as Float) == (value: 0, exact: true))
  expectTrue(Double._convert(from: -0.0 as Float) == (value: -0.0, exact: true))
  expectTrue(Double._convert(from: 1 as Float) == (value: 1, exact: true))
  expectTrue(Double._convert(from: -1 as Float) == (value: -1, exact: true))
  expectTrue(
    Double._convert(from: Float.infinity) == (value: .infinity, exact: true))
  expectTrue(
    Double._convert(from: -Float.infinity) == (value: -.infinity, exact: true))
  expectTrue(Double._convert(from: Float.nan).value.isNaN)
  expectTrue(Float._convert(from: Double.nan).value.isNaN)
  expectFalse(Double._convert(from: Float.nan).value.isSignalingNaN)
  expectFalse(Float._convert(from: Double.nan).value.isSignalingNaN)
  expectTrue(Double._convert(from: Float.signalingNaN).value.isNaN)
  expectTrue(Float._convert(from: Double.signalingNaN).value.isNaN)

  let x = Float(bitPattern: Float.nan.bitPattern | 0xf)
  expectEqual(
    Float._convert(from: Double._convert(from: x).value).value.bitPattern,
    x.bitPattern)
  var y = Double(bitPattern: Double.nan.bitPattern | 0xf)
  expectEqual(
    Double._convert(from: Float._convert(from: y).value).value.bitPattern,
    y.bitPattern)
  y = Double(bitPattern: Double.nan.bitPattern | (1 << 32 - 1))
  expectNotEqual(
    Double._convert(from: Float._convert(from: y).value).value.bitPattern,
    y.bitPattern)
  expectTrue(Float._convert(from: y).value.isNaN)
  expectFalse(Float._convert(from: y).exact)

  expectTrue(
    Float._convert(from: Double.leastNonzeroMagnitude) ==
      (value: 0, exact: false))
  expectTrue(
    Float._convert(from: -Double.leastNonzeroMagnitude) ==
      (value: -0.0, exact: false))
  expectTrue(
    Double._convert(from: Double.leastNonzeroMagnitude) ==
      (value: .leastNonzeroMagnitude, exact: true))
  expectTrue(
    Double._convert(from: -Double.leastNonzeroMagnitude) ==
      (value: -.leastNonzeroMagnitude, exact: true))

  y = Double._convert(from: Float.leastNonzeroMagnitude).value / 2
  expectTrue(Float._convert(from: y) == (value: 0, exact: false))
  y.negate()
  expectTrue(Float._convert(from: y) == (value: -0.0, exact: false))
  y.negate()
  y = y.nextUp
  expectTrue(
    Float._convert(from: y) == (value: .leastNonzeroMagnitude, exact: false))
  y.negate()
  expectTrue(
    Float._convert(from: y) == (value: -.leastNonzeroMagnitude, exact: false))

  expectEqual(
    Float._convert(from: Double.leastNormalMagnitude).value,
    Float(Double.leastNormalMagnitude))
  expectEqual(
    Float._convert(from: -Double.leastNormalMagnitude).value,
    Float(-Double.leastNormalMagnitude))

  expectEqual(Float._convert(from: Double.pi).value, 3.14159265)

  y = Double._convert(from: Float._convert(from: Double.pi).value).value.nextUp
  expectEqual(Float._convert(from: y).value, 3.14159265)
  y.negate()
  expectEqual(Float._convert(from: y).value, -3.14159265)

  expectTrue(
    Float._convert(from: Double.greatestFiniteMagnitude) ==
      (value: .infinity, exact: false))
  expectTrue(
    Float._convert(from: -Double.greatestFiniteMagnitude) ==
      (value: -.infinity, exact: false))
  expectTrue(
    Double._convert(from: Double.greatestFiniteMagnitude) ==
      (value: .greatestFiniteMagnitude, exact: true))
  expectTrue(
    Double._convert(from: -Double.greatestFiniteMagnitude) ==
      (value: -.greatestFiniteMagnitude, exact: true))

  expectEqual(
    Float._convert(
      from: Double._convert(from: Float.greatestFiniteMagnitude).value).value,
    Float.greatestFiniteMagnitude)
  expectEqual(
    Float._convert(
      from: Double._convert(from: Float.leastNonzeroMagnitude).value).value,
    Float.leastNonzeroMagnitude)

  if #available(macOS 11, iOS 14, watchOS 7, tvOS 14, *) {
    // The behavior tested here was introduced in
    // https://github.com/apple/swift/pull/30194

    // Let's make sure that the correct value is returned when two representable
    // values are equally close to the original value.
    let bitPattern: UInt64 = 0b01111111111_0000000000000000000000110000000000000000000000000000
    var z = Double(bitPattern: bitPattern)
    expectEqual(Float._convert(from: z).value, Float(z))

    z = Double(Float.greatestFiniteMagnitude) +
    Double(Float.greatestFiniteMagnitude.ulp / 2)
    expectEqual(Float._convert(from: z).value, Float(z))
  }
}

func positiveOne<T: ExpressibleByIntegerLiteral>() -> T {
  return 1
}
func negativeOne<T: ExpressibleByIntegerLiteral>() -> T {
  return -1
}

FloatingPoint.test("Float/ExpressibleByIntegerLiteral") {
  expectEqual(positiveOne(),  1.0 as Float)
  expectEqual(negativeOne(), -1.0 as Float)
}

FloatingPoint.test("Float/ExpressibleByFloatLiteral") {
  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)
#if !arch(i386) // i386 does not support a signaling nans.
  expectBitwiseEqual(bitPattern: 0x7fa0_0000, Ty.signalingNaN)
#endif
  expectBitwiseEqual(bitPattern: 0x7f80_0000, Ty.infinity)
  expectBitwiseEqual(0x1.ffff_fe__p127, Ty.greatestFiniteMagnitude)
  expectBitwiseEqual(0x1.921f_b4__p1, Ty.pi)
  expectBitwiseEqual(0x1.0p-23, Ty.ulpOfOne)
  expectBitwiseEqual(0x1.0p-126, Ty.leastNormalMagnitude)
#if arch(arm)
  expectBitwiseEqual(0x1.0p-126, Ty.leastNonzeroMagnitude)
#else
  expectBitwiseEqual(0x1.0p-149, Ty.leastNonzeroMagnitude)
#endif

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

// Tests the float and int conversions work correctly. Each case is special.

#if !os(macOS) && !(os(iOS) && targetEnvironment(macCatalyst))
if #available(iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
  FloatingPoint.test("Float16/Int") {
    expectNil(Int(exactly: Float16.infinity))
    expectNil(Int(exactly: -Float16.infinity))
  }
}
#endif

FloatingPoint.test("Float/UInt8") {
  expectEqual(UInt8.min, UInt8(Float(UInt8.min)))
  expectEqual(UInt8.max, UInt8(Float(UInt8.max)))
}

FloatingPoint.test("Float/Int8") {
  expectEqual(Int8.min, Int8(Float(Int8.min)))
  expectEqual(Int8.max, Int8(Float(Int8.max)))
}

FloatingPoint.test("Float/UInt16") {
  expectEqual(UInt16.min, UInt16(Float(UInt16.min)))
  expectEqual(UInt16.max, UInt16(Float(UInt16.max)))
}

FloatingPoint.test("Float/Int16") {
  expectEqual(Int16.min, Int16(Float(Int16.min)))
  expectEqual(Int16.max, Int16(Float(Int16.max)))
}

FloatingPoint.test("Float/UInt32")
.require(.crashTesting)
.code {
  expectEqual(UInt32.min, UInt32(Float(UInt32.min)))
  expectCrashLater()
  expectEqual(UInt32.max, UInt32(Float(UInt32.max)))
}

FloatingPoint.test("Float/Int32")
.require(.crashTesting)
.code {
  expectEqual(Int32.min, Int32(Float(Int32.min)))
  expectCrashLater()
  expectEqual(Int32.max, Int32(Float(Int32.max)))
}

FloatingPoint.test("Float/UInt64")
.require(.crashTesting)
.code {
  expectEqual(UInt64.min, UInt64(Float(UInt64.min)))
  expectCrashLater()
  expectEqual(UInt64.max, UInt64(Float(UInt64.max)))
}

FloatingPoint.test("Float/Int64")
.require(.crashTesting)
.code {
  expectEqual(Int64.min, Int64(Float(Int64.min)))
  expectCrashLater()
  expectEqual(Int64.max, Int64(Float(Int64.max)))
}

FloatingPoint.test("Double/ExpressibleByIntegerLiteral") {
  expectEqual(positiveOne(),  1.0 as Double)
  expectEqual(negativeOne(), -1.0 as Double)
}

FloatingPoint.test("Double/ExpressibleByFloatLiteral") {
  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)
#if !arch(i386) // i386 does not support a signaling nans.
  expectBitwiseEqual(bitPattern: 0x7ff4_0000_0000_0000, Ty.signalingNaN)
#endif
  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)
#if arch(arm)
  expectBitwiseEqual(0x1.0p-1022, Ty.leastNonzeroMagnitude)
#else
  expectBitwiseEqual(0x1.0p-1074, Ty.leastNonzeroMagnitude)
#endif

  // 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)))
}

FloatingPoint.test("Double/Int8") {
  expectEqual(Int8.min, Int8(Double(Int8.min)))
  expectEqual(Int8.max, Int8(Double(Int8.max)))
}

FloatingPoint.test("Double/UInt16") {
  expectEqual(UInt16.min, UInt16(Double(UInt16.min)))
  expectEqual(UInt16.max, UInt16(Double(UInt16.max)))
}

FloatingPoint.test("Double/Int16") {
  expectEqual(Int16.min, Int16(Double(Int16.min)))
  expectEqual(Int16.max, Int16(Double(Int16.max)))
}

FloatingPoint.test("Double/UInt32") {
  expectEqual(UInt32.min, UInt32(Double(UInt32.min)))
  expectEqual(UInt32.max, UInt32(Double(UInt32.max)))
}

FloatingPoint.test("Double/Int32") {
  expectEqual(Int32.min, Int32(Double(Int32.min)))
  expectEqual(Int32.max, Int32(Double(Int32.max)))
}

FloatingPoint.test("Double/UInt64")
.require(.crashTesting)
.code {
  expectEqual(UInt64.min, UInt64(Double(UInt64.min)))
  expectCrashLater()
  expectEqual(UInt64.max, UInt64(Double(UInt64.max)))
}

FloatingPoint.test("Double/Int64")
.require(.crashTesting)
.code {
  expectEqual(Int64.min, Int64(Double(Int64.min)))
  expectCrashLater()
  expectEqual(Int64.max, Int64(Double(Int64.max)))
}

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

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

#if arch(arm)
% for FloatSelf in ['Float32', 'Float64']:
func testSubNormalFlush(_ f: ${FloatSelf}) {
  if !f.isSubnormal {
    return
  }
  switch f.sign {
  case .plus:
    expectBitwiseEqual(.leastNonzeroMagnitude, f.nextUp)
    expectBitwiseEqual(0.0, f.nextDown)
  case .minus:
    expectBitwiseEqual(-0.0, f.nextUp)
    expectBitwiseEqual(-.leastNonzeroMagnitude, f.nextDown)
  }
}
% end
#endif

extension FloatingPoint {
  public var isQuietNaN: Bool { return isNaN && !isSignalingNaN }
}

func genericAbs<T: SignedNumeric & Comparable>(_ x: T) -> T {
  return abs(x)
}


%for Self in ['Float', 'Double', 'Float80']:
% if Self == 'Float80':
#if !os(Windows) && (arch(i386) || arch(x86_64))
% end
FloatingPoint.test("${Self}.round") {
  for rule in [FloatingPointRoundingRule.toNearestOrAwayFromZero,
               FloatingPointRoundingRule.toNearestOrEven,
               FloatingPointRoundingRule.towardZero,
               FloatingPointRoundingRule.awayFromZero,
               FloatingPointRoundingRule.up,
               FloatingPointRoundingRule.down] {

    //  Zeros, integers and infinities round to themselves:
    for value in [${Self}(), 1, 1/${Self}.ulpOfOne,
                  .greatestFiniteMagnitude, .infinity] {
      expectBitwiseEqual(value, value.rounded(rule))
      expectBitwiseEqual(-value, (-value).rounded(rule))
    }

    //  NaNs "round" to NaNs:
    expectTrue(${Self}.nan.rounded(rule).isNaN)

    //  Now let's try some inexact cases; we're going to stay close to zero,
    //  and check values close to (half-)integers, because those are the cases
    //  that people usually get wrong, and they'll reveal simple blunders like
    //  simply implementing the wrong rounding mode.
    for base in stride(from: ${Self}(-3.5), to: 4, by: 0.5) {
      for value in [base.nextDown, base, base.nextUp] {
        let result = value.rounded(rule)
        //  Result must be integral.  Since we're testing small values, we
        //  can simply check that Self(Int(result)) == result.  For larger
        //  values this wouldn't be a correct test.'
        expectEqual(${Self}(Int(result)), result)
        let residual = value - result
        //  For any rounding rule, abs(residual) must be less than 1, however
        //  due to rounding the computation can produce 1 exactly.
        expectTrue(abs(residual) <= 1)
        //  Remaining validation checks depend on the rounding rule.
        switch rule {
        case .toNearestOrAwayFromZero:
          expectTrue(abs(residual) < 0.5 ||
                     abs(residual) == 0.5 && abs(result) > abs(value))
        case .toNearestOrEven:
          expectTrue(abs(residual) < 0.5 ||
                     abs(residual) == 0.5 && Int(result) % 2 == 0)
        case .towardZero:
          expectTrue(abs(result) <= abs(value))
        case .awayFromZero:
          expectTrue(abs(result) >= abs(value))
        case .up:
          expectTrue(result >= value)
        case .down:
          expectTrue(result <= value)
        }
      }
    }
  }
}

FloatingPoint.test("${Self}.remainder") {
  //  Basic soundness tests only; these are only sufficient to provide reassurance
  //  that a known-good remainder function (e.g. from the C stdlib) has been
  //  shimmed correctly.  They are not sufficient for development of such a
  //  function, and should not be employed for that purpose.
  expectTrue(${Self}(0).remainder(dividingBy: 0).isNaN)
  expectTrue(${Self}(1).remainder(dividingBy: 0).isNaN)
  expectTrue(${Self}.infinity.remainder(dividingBy: 0).isNaN)
  expectTrue(${Self}.infinity.remainder(dividingBy: 1).isNaN)
  expectEqual(0, ${Self}(0).remainder(dividingBy: .infinity))
  expectEqual(1, ${Self}(1).remainder(dividingBy: .infinity))
  expectEqual(-1, ${Self}(2).remainder(dividingBy: 3))
  expectEqual(-1, ${Self}(3).remainder(dividingBy: 2))
  expectEqual(1, ${Self}(5).remainder(dividingBy: 2))
}

FloatingPoint.test("${Self}.squareRoot") {
  //  Basic soundness tests only; these are only sufficient to provide reassurance
  //  that a known-good square root function (e.g. from the C stdlib) has been
  //  shimmed correctly.  They are not sufficient for development of such a
  //  function, and should not be employed for that purpose.
  expectTrue(${Self}(-1).squareRoot().isNaN)
  expectTrue(${Self}.nan.squareRoot().isNaN)
  expectEqual(-0, ${Self}(-0).squareRoot())
  expectEqual(0, ${Self}(0).squareRoot())
  expectEqual(1, ${Self}(1).squareRoot())
  expectEqual(2, ${Self}(4).squareRoot())
  expectEqual(.infinity, ${Self}.infinity.squareRoot())
}

FloatingPoint.test("${Self}.addingProduct") {
  //  Fails if fma( ) is incorrectly implemented using separate + and *,
  //  and validates that we have the argument order right for the shimmed
  //  function.
  let one = ${Self}(1)
  let ulp = ${Self}.ulpOfOne
  expectEqual(ulp*ulp, one.addingProduct(ulp + one, ulp - one))
}

FloatingPoint.test("${Self}/LosslessStringConvertible") {
  let instances = [
    1.0, -1.0,
    0.0, -0.0,
    ${Self}.infinity, -${Self}.infinity
  ]

  checkLosslessStringConvertible(instances)
  expectTrue(Float(String(Float.nan))!.isNaN)
}

FloatingPoint.test("${Self}.significandWidth") {
  expectEqual(-1, ${Self}(0).significandWidth)
  expectEqual(-1, ${Self}.infinity.significandWidth)
  expectEqual(-1, ${Self}.nan.significandWidth)
  expectEqual(${Self}.significandBitCount, ${Self}(1).nextUp.significandWidth)
  expectEqual(${Self}.significandBitCount, ${Self}(1).nextDown.significandWidth)
  expectEqual(0, ${Self}.ulpOfOne.significandWidth)
  expectEqual(0, ${Self}(1).significandWidth)
  expectEqual(0, ${Self}(2).significandWidth)
  expectEqual(1, ${Self}(3).significandWidth)
}

FloatingPoint.test("${Self}.absNegativeZero") {
  expectEqual(abs(${Self}(-0.0)), ${Self}(0.0))
  expectEqual(genericAbs(${Self}(-0.0)), ${Self}(0.0))
}

% if Self == 'Float80':
#endif
% end
%end

let floatNextUpDownTests: [(Float, Float)] = [
  (.greatestFiniteMagnitude, .infinity),
  (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
#if arch(arm)
  if prev.isSubnormal || succ.isSubnormal {
    testSubNormalFlush(prev)
    testSubNormalFlush(succ)
    return
  }
#endif
  expectBitwiseEqual(succ, prev.nextUp)
  expectBitwiseEqual(prev, succ.nextDown)
  expectBitwiseEqual(-succ, (-prev).nextDown)
  expectBitwiseEqual(-prev, (-succ).nextUp)
}

let doubleNextUpDownTests: [(Double, Double)] = [
  (.greatestFiniteMagnitude, .infinity),
  (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
#if arch(arm)
  if prev.isSubnormal || succ.isSubnormal {
    testSubNormalFlush(prev)
    testSubNormalFlush(succ)
    return
  }
#endif
  expectBitwiseEqual(succ, prev.nextUp)
  expectBitwiseEqual(prev, succ.nextDown)
  expectBitwiseEqual(-succ, (-prev).nextDown)
  expectBitwiseEqual(-prev, (-succ).nextUp)
}

%for Self in ['Float', 'Double']:
FloatingPoint.test("${Self}.nextUp, .nextDown/nan") {
  let x = ${Self}.nan
  expectTrue(x.nextUp.isNaN)
  expectTrue(x.nextDown.isNaN)
  expectTrue((-x).nextDown.isNaN)
  expectTrue((-x).nextUp.isNaN)
}
%end

#if !os(Windows) && (arch(i386) || arch(x86_64))

FloatingPoint.test("Float80/ExpressibleByIntegerLiteral") {
  expectEqual(positiveOne(),  1.0 as Float80)
  expectEqual(negativeOne(), -1.0 as Float80)
}

FloatingPoint.test("Float80/ExpressibleByFloatLiteral") {
  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)
#if !arch(i386) // i386 does not support a signaling nans.
  expectBitwiseEqual(bitPattern: 0x7ff4_0000_0000_0000, Ty.signalingNaN)
#endif
  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']:

func checkFloatingPointComparison_${FloatSelf}(
  _ expected: ExpectedComparisonResult,
  _ lhs: ${FloatSelf}, _ rhs: ${FloatSelf},
  //===--- TRACE boilerplate ----------------------------------------------===//
  // @autoclosure _ message: () -> String = "",
  showFrame: Bool = true,
  stackTrace: SourceLocStack = SourceLocStack(),
  file: String = #file, line: UInt = #line
) {
  let newTrace = stackTrace.pushIf(showFrame, file: file, line: line)
  let message = { "expected: lhs=\(lhs) \(expected) rhs=\(rhs)" }
  expectEqual(expected.isEQ(), lhs == rhs, message(), stackTrace: newTrace)
  expectEqual(expected.isNE(), lhs != rhs, message(), stackTrace: newTrace)
  checkHashable(
    expectedEqual: expected.isEQ(),
    lhs, rhs, message(), stackTrace: newTrace)

  expectEqual(expected.isLT(), lhs < rhs, message(), stackTrace: newTrace)
  expectEqual(expected.isLE(), lhs <= rhs, message(), stackTrace: newTrace)
  expectEqual(expected.isGE(), lhs >= rhs, message(), stackTrace: newTrace)
  expectEqual(expected.isGT(), lhs > rhs, message(), stackTrace: newTrace)
  checkComparable(expected, lhs, rhs, message(), stackTrace: newTrace)
}

FloatingPoint.test("${FloatSelf}/{Comparable,Hashable,Equatable}") {
// On arm we flush subnormals to zero so testing subnormals won't work.
#if arch(arm)
  let interestingValues: [${FloatSelf}] = [
    // Interesting floating point values, sorted.
    -${FloatSelf}.infinity,
    -${FloatSelf}.greatestFiniteMagnitude,
    -1.0,
    -${FloatSelf}.ulpOfOne,
    -${FloatSelf}.leastNormalMagnitude,
    -0.0,
    0.0,
    ${FloatSelf}.leastNormalMagnitude,
    ${FloatSelf}.ulpOfOne,
    1.0,
    ${FloatSelf}.greatestFiniteMagnitude,
    ${FloatSelf}.infinity,
    ${FloatSelf}.nan,
    ${FloatSelf}.signalingNaN,
  ]
#else
  let interestingValues: [${FloatSelf}] = [
    // Interesting floating point values, sorted.
    -${FloatSelf}.infinity,
    -${FloatSelf}.greatestFiniteMagnitude,
    -1.0,
    -${FloatSelf}.ulpOfOne,
    -${FloatSelf}.leastNormalMagnitude,
    -${FloatSelf}.leastNormalMagnitude/2,
    -${FloatSelf}.leastNonzeroMagnitude,
    -0.0,
    0.0,
    ${FloatSelf}.leastNonzeroMagnitude,
    ${FloatSelf}.leastNormalMagnitude/2,
    ${FloatSelf}.leastNormalMagnitude,
    ${FloatSelf}.ulpOfOne,
    1.0,
    ${FloatSelf}.greatestFiniteMagnitude,
    ${FloatSelf}.infinity,
    ${FloatSelf}.nan,
    ${FloatSelf}.signalingNaN,
  ]
#endif

  for lhsIdx in interestingValues.indices {
    for rhsIdx in interestingValues.indices {
      let lhs = interestingValues[lhsIdx]
      let rhs = interestingValues[rhsIdx]
      if lhs.isZero && rhs.isZero {
        // Special case: 0.0 and -0.0 compare equal.
        checkFloatingPointComparison_${FloatSelf}(
          ExpectedComparisonResult.eq, lhs, rhs)
      } else if lhs.isNaN || rhs.isNaN {
        // Special case: NaN is unordered wrt other values.
        // - equality comparison with NaN returns false,
        // - NaN is not equal to anything, including NaN.
        expectFalse(lhs == rhs)
        expectTrue(lhs != rhs)

        expectFalse(lhs < rhs)
        expectFalse(lhs <= rhs)
        expectFalse(lhs >= rhs)
        expectFalse(lhs > rhs)
      } else {
        // The sound case.
        checkFloatingPointComparison_${FloatSelf}(
          lhsIdx < rhsIdx ?
            ExpectedComparisonResult.lt :
            (lhsIdx == rhsIdx ?
              ExpectedComparisonResult.eq :
              ExpectedComparisonResult.gt),
          lhs, rhs)
      }

      //  Check minimum, maximum, minimumMagnitude and maximumMagnitude.
      let min = ${FloatSelf}.minimum(lhs, rhs)
      let max = ${FloatSelf}.maximum(lhs, rhs)
      let minMag = ${FloatSelf}.minimumMagnitude(lhs, rhs)
      let maxMag = ${FloatSelf}.maximumMagnitude(lhs, rhs)
      //  If either lhs or rhs is signaling, or if both are quiet NaNs, the
      //  result is a quiet NaN.
      if lhs.isSignalingNaN || rhs.isSignalingNaN || (lhs.isNaN && rhs.isNaN) {
        // FIXME: <rdar://problem/48917925>
        // expectTrue(min.isQuietNaN)
        // expectTrue(max.isQuietNaN)
        // expectTrue(minMag.isQuietNaN)
        // expectTrue(maxMag.isQuietNaN)
      }
      //  If only one of lhs and rhs is NaN, the result of the min/max
      //  operations is always the other value.  While contrary to all other
      //  IEEE 754 basic operations, this property is critical to ensure
      //  that clamping to a valid range behaves as expected.
      else if lhs.isNaN && !rhs.isNaN {
        expectEqual(min.bitPattern, rhs.bitPattern)
        expectEqual(max.bitPattern, rhs.bitPattern)
        expectEqual(minMag.bitPattern, rhs.bitPattern)
        expectEqual(maxMag.bitPattern, rhs.bitPattern)
      }
      else if rhs.isNaN && !lhs.isNaN {
        expectEqual(min.bitPattern, lhs.bitPattern)
        expectEqual(max.bitPattern, lhs.bitPattern)
        expectEqual(minMag.bitPattern, lhs.bitPattern)
        expectEqual(maxMag.bitPattern, lhs.bitPattern)
      }
      //  If lhs and rhs are equal, min is lhs and max is rhs.  This ensures
      //  that the set {lhs, rhs} is the same as the set {min, max} so long
      //  as lhs and rhs are non-NaN.  This is less important for min/max than
      //  it is for minMag and maxMag, but it makes sense to define this way.
      if lhs <= rhs {
        expectEqual(min.bitPattern, lhs.bitPattern)
        expectEqual(max.bitPattern, rhs.bitPattern)
      } else if lhs > rhs {
        expectEqual(max.bitPattern, lhs.bitPattern)
        expectEqual(min.bitPattern, rhs.bitPattern)
      }
      //  If lhs and rhs have equal magnitude, minMag is lhs and maxMag is rhs.
      //  This ensures that the set {lhs, rhs} is the same as the set
      //  {minMag, maxMag} so long as lhs and rhs are non-NaN; this is a
      //  restriction of the IEEE 754 rules, but it makes good sense and also
      //  makes this primitive more useful for building head-tail arithmetic
      //  operations.
      if abs(lhs) <= abs(rhs) {
        expectEqual(minMag.bitPattern, lhs.bitPattern)
        expectEqual(maxMag.bitPattern, rhs.bitPattern)
      } else if abs(lhs) > abs(rhs) {
        expectEqual(maxMag.bitPattern, lhs.bitPattern)
        expectEqual(minMag.bitPattern, rhs.bitPattern)
      }
    }
  }
}

% end

% for Self in ['Float32', 'Float64', 'Float80']:
#if ${'!os(Windows) && (arch(i386) || arch(x86_64))' if Self == 'Float80' else 'true'}
FloatingPoint.test("${Self}/Strideable") {
  // FIXME: the test data could probably be better chosen here, to
  // exercise more cases.  Note: NaNs (and possibly Infs) are singular
  // values with respect to Strideable conformance and aren't expected
  // to pass these tests.
  let instances: [${Self}] = [-1.0, 0.0, 0.5, 1.0, 1E20]
  checkStrideable(
    instances, strides: instances,
    distanceOracle: { instances[$1] - instances[$0] },
    advanceOracle: { instances[$0] + instances[$1] })
}
#endif
% end

FloatingPoint.test("Float32/Literals") {
  do {
    let f: Float32 = 0.0
    expectEqual(0x0000_0000, f.bitPattern)
  }
  do {
    let f: Float32 = -0.0
    expectEqual(0x8000_0000, f.bitPattern)
  }

  do {
    let f: Float32 = 1.0
    expectEqual(0x3f80_0000, f.bitPattern)
  }
  do {
    let f: Float32 = -1.0
    expectEqual(0xbf80_0000, f.bitPattern)
  }

  do {
    let f: Float32 = 0.999999
    expectEqual(0x3f7fffef, f.bitPattern)
  }
  do {
    let f: Float32 = 0.9999999
    expectEqual(0x3f7ffffe, f.bitPattern)
  }
  do {
    let f: Float32 = 0.99999999
    expectEqual(0x3f80_0000, f.bitPattern)
  }

  // Smallest subnormal.
  do {
    let f: Float32 = 1.4e-45
    expectEqual(0x0000_0001, f.bitPattern)
  }
  do {
    let f: Float32 = -1.4e-45
    expectEqual(0x8000_0001, f.bitPattern)
  }

  // Rounded to zero.
  do {
    let f: Float32 = 0.7e-45
    expectEqual(0x0000_0000, f.bitPattern)
  }
  do {
    let f: Float32 = -0.7e-45
    expectEqual(0x8000_0000, f.bitPattern)
  }

  // Second largest normal.
  do {
    let f: Float32 = 3.4028232e+38
    expectEqual(0x7f7f_fffe, f.bitPattern)
  }
  do {
    let f: Float32 = -3.4028232e+38
    expectEqual(0xff7f_fffe, f.bitPattern)
  }

  // Largest normal.
  do {
    let f: Float32 = 3.4028234e+38
    expectEqual(0x7f7f_ffff, f.bitPattern)
  }
  do {
    let f: Float32 = 340282340000000000000000000000000000000.0
    expectEqual(0x7f7f_ffff, f.bitPattern)
  }
  do {
    let f: Float32 = 340282340000000000000000000000000000000
    expectEqual(0x7f7f_ffff, f.bitPattern)
  }
  do {
    let f: Float32 = -3.4028234e+38
    expectEqual(0xff7f_ffff, f.bitPattern)
  }
  do {
    let f: Float32 = -340282340000000000000000000000000000000.0
    expectEqual(0xff7f_ffff, f.bitPattern)
  }
  do {
    let f: Float32 = -340282340000000000000000000000000000000
    expectEqual(0xff7f_ffff, f.bitPattern)
  }
}

FloatingPoint.test("Float64/Literals") {
  do {
    let f: Float64 = 0.0
    expectEqual(0x0000_0000_0000_0000, f.bitPattern)
  }
  do {
    let f: Float64 = -0.0
    expectEqual(0x8000_0000_0000_0000, f.bitPattern)
  }

  do {
    let f: Float64 = 1.0
    expectEqual(0x3ff0_0000_0000_0000, f.bitPattern)
  }
  do {
    let f: Float64 = -1.0
    expectEqual(0xbff0_0000_0000_0000, f.bitPattern)
  }

  do {
    let f: Float64 = 0.999999999999999
    expectEqual(0x3fef_ffff_ffff_fff7, f.bitPattern)
  }
  do {
    let f: Float64 = 0.9999999999999999
    expectEqual(0x3fef_ffff_ffff_ffff, f.bitPattern)
  }
  do {
    let f: Float64 = 0.99999999999999999
    expectEqual(0x3ff0_0000_0000_0000, f.bitPattern)
  }

  // Smallest subnormal.
  do {
    let f: Float64 = 4.0e-324
    expectEqual(0x0000_0000_0000_0001, f.bitPattern)
  }
  do {
    let f: Float64 = -4.0e-324
    expectEqual(0x8000_0000_0000_0001, f.bitPattern)
  }

  // Rounded to zero.
  do {
    let f: Float64 = 2.4e-324
    expectEqual(0x0000_0000_0000_0000, f.bitPattern)
  }
  do {
    let f: Float64 = -2.4e-324
    expectEqual(0x8000_0000_0000_0000, f.bitPattern)
  }

  // Second largest normal.
  do {
    let f: Float64 = 1.79769313486231551e+308
    expectEqual(0x7fef_ffff_ffff_fffe, f.bitPattern)
  }
  do {
    let f: Float64 = -1.79769313486231551e+308
    expectEqual(0xffef_ffff_ffff_fffe, f.bitPattern)
  }

  // Largest normal.
  do {
    let f: Float64 = 1.7976931348623157e+308
    expectEqual(0x7fef_ffff_ffff_ffff, f.bitPattern)
  }
  do {
    let f: Float64 = 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0
    expectEqual(0x7fef_ffff_ffff_ffff, f.bitPattern)
  }
  do {
    let f: Float64 = 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    expectEqual(0x7fef_ffff_ffff_ffff, f.bitPattern)
  }
  do {
    let f: Float64 = -1.7976931348623157e+308
    expectEqual(0xffef_ffff_ffff_ffff, f.bitPattern)
  }
  do {
    let f: Float64 = -179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0
    expectEqual(0xffef_ffff_ffff_ffff, f.bitPattern)
  }
  do {
    let f: Float64 = -179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    expectEqual(0xffef_ffff_ffff_ffff, f.bitPattern)
  }
}

#if !os(Windows) && (arch(i386) || arch(x86_64))

FloatingPoint.test("Float80/Literals") {
  do {
    let f: Float80 = 0.0
    expectEqual(Float80Bits(0x0000, 0x0000_0000_0000_0000), f.bitPattern)
  }
  do {
    let f: Float80 = -0.0
    expectEqual(Float80Bits(0x8000, 0x0000_0000_0000_0000), f.bitPattern)
  }

  do {
    let f: Float80 = 1.0
    expectEqual(Float80Bits(0x3fff, 0x8000_0000_0000_0000), f.bitPattern)
  }
  do {
    let f: Float80 = -1.0
    expectEqual(Float80Bits(0xbfff, 0x8000_0000_0000_0000), f.bitPattern)
  }

  do {
    let f: Float80 = 0.999999999999999999
    expectEqual(Float80Bits(0x3ffe, 0xffff_ffff_ffff_ffee), f.bitPattern)
  }
  do {
    let f: Float80 = 0.9999999999999999999
    expectEqual(Float80Bits(0x3ffe, 0xffff_ffff_ffff_fffe), f.bitPattern)
  }
  do {
    let f: Float80 = 0.99999999999999999995
    expectEqual(Float80Bits(0x3ffe, 0xffff_ffff_ffff_ffff), f.bitPattern)
  }
  do {
    let f: Float80 = 0.99999999999999999999
    expectEqual(Float80Bits(0x3fff, 0x8000_0000_0000_0000), f.bitPattern)
  }

  // Smallest subnormal.
  do {
    // 3.645199531882474602528e-4951
    let f: Float80 = 3.6e-4951
    expectEqual(Float80Bits(0x0000, 0x0000_0000_0000_0001), f.bitPattern)
  }
  do {
    let f: Float80 = -3.6e-4951
    expectEqual(Float80Bits(0x8000, 0x0000_0000_0000_0001), f.bitPattern)
  }

  // Rounded to zero.
  do {
    let f: Float80 = 1.8e-4951
    expectEqual(Float80Bits(0x0000, 0x0000_0000_0000_0000), f.bitPattern)
  }
  do {
    let f: Float80 = -1.8e-4951
    expectEqual(Float80Bits(0x8000, 0x0000_0000_0000_0000), f.bitPattern)
  }

  // Largest normal.
  do {
    let f: Float80 = 1.189731495357231765e+4932
    expectEqual(Float80Bits(0x7ffe, 0xffff_ffff_ffff_ffff), f.bitPattern)
  }
  do {
    let f: Float80 = [encoded data, 4933 characters].0
    expectEqual(Float80Bits(0x7ffe, 0xffff_ffff_ffff_ffff), f.bitPattern)
  }
  do {
    let f: Float80 = -1.189731495357231765e+4932
    expectEqual(Float80Bits(0xfffe, 0xffff_ffff_ffff_ffff), f.bitPattern)
  }
  do {
    let f: Float80 = [encoded data, 4934 characters].0
    expectEqual(Float80Bits(0xfffe, 0xffff_ffff_ffff_ffff), f.bitPattern)
  }
}

#endif

FloatingPoint.test("Float32/quietNaN") {
  do {
    let f: Float32 = .nan
    expectTrue(f.isNaN && !f.isSignalingNaN)
    expectEqual(0x7fc0_0000, f.bitPattern)
  }
  do {
    // Empty payload
    let f: Float32 = Float32(bitPattern: 0x7fc0_0000)
    expectTrue(f.isNaN && !f.isSignalingNaN)
  }
  do {
    // Full payload
    let f: Float32 = Float32(bitPattern: 0x7fff_ffff)
    expectTrue(f.isNaN && !f.isSignalingNaN)
  }
  do {
    // Highest payload `init(nan:signaling:)` can handle
    let f: Float32 = Float32(nan: 0x1f_ffff, signaling: false)
    expectTrue(f.isNaN && !f.isSignalingNaN)
    expectEqual(0x7fdf_ffff, f.bitPattern)
  }
}

FloatingPoint.test("Float32/quietNaN overflow")
.require(.crashTesting)
.code {
  // Payload overflow
  expectCrashLater()
  _ = Float32(nan: 0x20_0000, signaling: false)
}

FloatingPoint.test("Float64/quietNaN") {
  do {
    let f: Float64 = .nan
    expectTrue(f.isNaN && !f.isSignalingNaN)
    expectEqual(0x7ff8_0000_0000_0000, f.bitPattern)
  }
  do {
    // Empty payload
    let f: Float64 = Float64(bitPattern: 0x7ff8_0000_0000_0000)
    expectTrue(f.isNaN && !f.isSignalingNaN)
  }
  do {
    // Full payload
    let f: Float64 = Float64(bitPattern: 0x7fff_ffff_ffff_ffff)
    expectTrue(f.isNaN && !f.isSignalingNaN)
  }
  do {
    // Highest payload `init(nan:signaling:)` can handle
    let f: Float64 = Float64(nan: 0x3_ffff_ffff_ffff, signaling: false)
    expectTrue(f.isNaN && !f.isSignalingNaN)
    expectEqual(0x7ffb_ffff_ffff_ffff, f.bitPattern)
  }
}

FloatingPoint.test("Float64/quietNaN overflow")
.require(.crashTesting)
.code {
  // Payload overflow
  expectCrashLater()
  _ = Float64(nan: 0x4_0000_0000_0000, signaling: false)
}

#if !os(Windows) && (arch(i386) || arch(x86_64))

FloatingPoint.test("Float80/quietNaN") {
  do {
    let f: Float80 = .nan
    expectTrue(f.isNaN && !f.isSignalingNaN)
    expectEqual(Float80Bits(0x7fff, 0xc000_0000_0000_0000), f.bitPattern)
  }
  do {
    // Empty payload
    let f: Float80 = Float80(bitPattern: Float80Bits(0x7fff, 0xc000_0000_0000_0000))
    expectTrue(f.isNaN && !f.isSignalingNaN)
  }
  do {
    // Full payload
    let f: Float80 = Float80(bitPattern: Float80Bits(0x7fff, 0xffff_ffff_ffff_ffff))
    expectTrue(f.isNaN && !f.isSignalingNaN)
  }
  do {
    // Highest payload `init(nan:signaling:)` can handle
    let f: Float80 = Float80(nan: 0x1fff_ffff_ffff_ffff, signaling: false)
    expectTrue(f.isNaN && !f.isSignalingNaN)
    expectEqual(Float80Bits(0x7fff, 0xdfff_ffff_ffff_ffff), f.bitPattern)
  }
}

FloatingPoint.test("Float80/quietNaN overflow")
.require(.crashTesting)
.code {
  // Payload overflow
  expectCrashLater()
  _ = Float80(nan: 0x2000_0000_0000_0000, signaling: false)
}

#endif

#if !arch(i386)

FloatingPoint.test("Float32/signalingNaN") {
  do {
    let f: Float32 = .signalingNaN
    expectTrue(f.isNaN && f.isSignalingNaN)
    expectEqual(0x7fa0_0000, f.bitPattern)
  }
  do {
    // Empty payload
    let f: Float32 = Float32(bitPattern: 0x7fa0_0000)
    expectTrue(f.isNaN && f.isSignalingNaN)
  }
  do {
    // Full payload
    let f: Float32 = Float32(bitPattern: 0x7fbf_ffff)
    expectTrue(f.isNaN && f.isSignalingNaN)
  }
  do {
    // Highest payload `init(nan:signaling:)` can handle
    let f: Float32 = Float32(nan: 0x1f_ffff, signaling: true)
    expectTrue(f.isNaN && f.isSignalingNaN)
    expectEqual(0x7fbf_ffff, f.bitPattern)
  }
}

FloatingPoint.test("Float32/signalingNaN overflow")
.require(.crashTesting)
.code {
  // payload overflow
  expectCrashLater()
  _ = Float32(nan: 0x20_0000, signaling: true)
}

FloatingPoint.test("Float64/signalingNaN") {
  do {
    let f: Float64 = .signalingNaN
    expectTrue(f.isNaN && f.isSignalingNaN)
    expectEqual(0x7ff4_0000_0000_0000, f.bitPattern)
  }
  do {
    // Empty payload
    let f: Float64 = Float64(bitPattern: 0x7ff4_0000_0000_0000)
    expectTrue(f.isNaN && f.isSignalingNaN)
  }
  do {
    // Full payload
    let f: Float64 = Float64(bitPattern: 0x7ff7_ffff_ffff_ffff)
    expectTrue(f.isNaN && f.isSignalingNaN)
  }
  do {
    // Highest payload `init(nan:signaling:)` can handle
    let f: Float64 = Float64(nan: 0x3_ffff_ffff_ffff, signaling: true)
    expectTrue(f.isNaN && f.isSignalingNaN)
    expectEqual(0x7ff7_ffff_ffff_ffff, f.bitPattern)
  }
}

FloatingPoint.test("Float64/signalingNaN overflow")
.require(.crashTesting)
.code {
  // payload overflow
  expectCrashLater()
  _ = Float64(nan: 0x4_0000_0000_0000, signaling: true)
}

#endif

#if !os(Windows) && arch(x86_64)

FloatingPoint.test("Float80/signalingNaN") {
  do {
    let f: Float80 = .signalingNaN
    expectTrue(f.isNaN && f.isSignalingNaN)
    expectEqual(Float80Bits(0x7fff, 0xa000_0000_0000_0000), f.bitPattern)
  }
  do {
    // Empty payload
    let f: Float80 = Float80(bitPattern: Float80Bits(0x7fff, 0xa000_0000_0000_0000))
    expectTrue(f.isNaN && f.isSignalingNaN)
  }
  do {
    // Full payload
    let f: Float80 = Float80(bitPattern: Float80Bits(0x7fff, 0xbfff_ffff_ffff_ffff))
    expectTrue(f.isNaN && f.isSignalingNaN)
  }
  do {
    // Highest payload `init(nan:signaling:)` can handle
    let f: Float80 = Float80(nan: 0x1fff_ffff_ffff_ffff, signaling: true)
    expectTrue(f.isNaN && f.isSignalingNaN)
    expectEqual(Float80Bits(0x7fff, 0xbfff_ffff_ffff_ffff), f.bitPattern)
  }
}

FloatingPoint.test("Float80/signalingNaN overflow")
.require(.crashTesting)
.code {
  // payload overflow
  expectCrashLater()
  _ = Float80(nan: 0x2000_0000_0000_0000, signaling: true)
}

#endif

var FloatingPointClassification = TestSuite("FloatingPointClassification")

FloatingPointClassification.test("FloatingPointClassification/Hashable") {
  let values: [FloatingPointClassification] = [
    .signalingNaN,
    .quietNaN,
    .negativeInfinity,
    .negativeNormal,
    .negativeSubnormal,
    .negativeZero,
    .positiveZero,
    .positiveSubnormal,
    .positiveNormal,
    .positiveInfinity
  ]
  // Values should be equal iff indices equal
  checkHashable(values, equalityOracle: { $0 == $1 })
}

runAllTests()
