// Value encoding: map PLC values (coils, 16/32-bit integers) onto the raw
// 16-bit words that travel on the Modbus wire, honouring byte order and word
// order. This is the layer a driver uses to translate a point-table register
// into the bytes sent to / received from the slave.
//
// Conventions
// -----------
// A "word" is a 16-bit value stored as an `Int` in 0..=65535.
// Byte order says which of a word's two bytes is transmitted first.
// Word order says which of a 32-bit value's two words occupies the lower
// register address.
//
// All arithmetic stays inside the 32-bit `Int` range, so the code behaves
// identically on every backend without depending on 64-bit-wide globals.
///|
/// How the two bytes of a 16-bit word are placed on the wire.
pub enum ByteOrder {
/// Big endian: high byte transmitted first.
BigEndian
/// Little endian: low byte transmitted first.
LittleEndian
}
///|
/// In which register the high word of a 32-bit value is mapped.
pub enum WordOrder {
/// Native order: the high word occupies the lower register address.
HighWordLowAddress
/// Byte-swapped order: the low word occupies the lower register address.
LowWordLowAddress
}
///|
/// The same value laid out according to the reverse of an order.
fn swap_byte_order(order : ByteOrder) -> ByteOrder {
match order {
BigEndian => LittleEndian
LittleEndian => BigEndian
}
}
///|
/// The reverse of a word order.
fn swap_word_order(order : WordOrder) -> WordOrder {
match order {
HighWordLowAddress => LowWordLowAddress
LowWordLowAddress => HighWordLowAddress
}
}
///|
/// Human keyword for a byte order, for reports and (de)serialization.
pub fn byte_order_name(order : ByteOrder) -> String {
match order {
BigEndian => "big-endian"
LittleEndian => "little-endian"
}
}
///|
/// Resolve a keyword ("big"/"little", case-insensitive) into a `ByteOrder`,
/// defaulting to big-endian for anything unrecognised.
pub fn byte_order_of(name : String) -> ByteOrder {
if name == "little" || name == "le" || name == "LittleEndian" {
LittleEndian
} else {
BigEndian
}
}
///|
/// Resolve a keyword ("hi-lo"/"lo-hi", case-insensitive) into a `WordOrder`,
/// defaulting to native order (high word at the lower address).
pub fn word_order_of(name : String) -> WordOrder {
if name == "lo-hi" || name == "lo" || name == "LowWordLowAddress" {
LowWordLowAddress
} else {
HighWordLowAddress
}
}
///|
/// Human keyword for a word order, for reports and (de)serialization.
pub fn word_order_name(order : WordOrder) -> String {
match order {
HighWordLowAddress => "hi-lo"
LowWordLowAddress => "lo-hi"
}
}
///|
/// The two bytes (ints in 0..=255) of a 16-bit word under `order`.
pub fn uint16_to_bytes(w : Int, order : ByteOrder) -> (Int, Int) {
let hi = (w >> 8) & 0xFF
let lo = w & 0xFF
match order {
BigEndian => (hi, lo)
LittleEndian => (lo, hi)
}
}
///|
/// Rebuild a 16-bit word from two bytes (ints in 0..=255) under `order`.
/// The pair is `(first_byte, second_byte)` in wire order.
pub fn bytes_to_uint16(b0 : Int, b1 : Int, order : ByteOrder) -> Int {
match order {
BigEndian => (b0 << 8) | b1
LittleEndian => (b1 << 8) | b0
}
}
///|
/// The unsigned 16-bit word for a coil bit (0 or 1).
pub fn encode_coil(value : Bool) -> Int {
if value {
1
} else {
0
}
}
///|
/// Decode a coil bit from a 16-bit word; any non-zero value counts as on.
pub fn decode_coil(word : Int) -> Bool {
(word & 0xFFFF) != 0
}
///|
/// The unsigned 16-bit word for a `uint16` value (0..=65535).
pub fn encode_uint16(v : Int) -> Int {
v & 0xFFFF
}
///|
/// Decode a `uint16` value from a word (0..=65535).
pub fn decode_uint16(word : Int) -> Int {
word & 0xFFFF
}
///|
/// Map a signed `int16` (-32768..=32767) onto its unsigned 16-bit word.
pub fn encode_int16(v : Int) -> Int {
v & 0xFFFF
}
///|
/// Map an unsigned 16-bit word back to a signed `int16` (two's complement).
pub fn decode_int16(word : Int) -> Int {
let u = word & 0xFFFF
if u >= 0x8000 {
u - 0x10000
} else {
u
}
}
///|
/// The two bytes, in wire order for `byteOrder`, of a 16-bit value. This is the
/// minimal Modbus payload a single register occupies on the bus.
pub fn int16_bytes(v : Int, byteOrder : ByteOrder) -> Array[Int] {
let (hi, lo) = uint16_to_bytes(v & 0xFFFF, byteOrder)
[hi, lo]
}
///|
/// Rebuild a 16-bit word from a two-byte wire payload (ints in 0..=255).
pub fn int16_from_bytes(bytes : Array[Int], byteOrder : ByteOrder) -> Int {
bytes_to_uint16(bytes[0] & 0xFF, bytes[1] & 0xFF, byteOrder)
}
///|
test "int16 byte payloads round trip and respect byte order" {
let be = int16_bytes(0x1234, BigEndian)
let le = int16_bytes(0x1234, LittleEndian)
assert_eq(be, [0x12, 0x34])
assert_eq(le, [0x34, 0x12])
assert_eq(int16_from_bytes(be, BigEndian), 0x1234)
assert_eq(int16_from_bytes(le, LittleEndian), 0x1234)
// A signed view of the same payload.
assert_eq(decode_int16(int16_from_bytes(be, BigEndian)), 4660)
}
///|
test "int16 wire round trip covers signed extremes in both byte orders" {
let vals = [0, 1, -1, 32767, -32768, -248]
for v in vals {
for bo in [BigEndian, LittleEndian] {
let bs = int16_bytes(v, bo)
// Reassemble the unsigned word, then pull out the two's-complement sign.
let w = int16_from_bytes(bs, bo)
assert_eq(w & 0xFFFF, encode_int16(v))
assert_eq(decode_int16(w & 0xFFFF), v)
}
}
}
///|
/// Split a 32-bit `int` into its high and low 16-bit words (unsigned).
pub fn int32_parts(v : Int) -> (Int, Int) {
let hi = (v >> 16) & 0xFFFF
let lo = v & 0xFFFF
(hi, lo)
}
///|
/// Fold two unsigned 16-bit words back into a signed 32-bit `int`.
/// Because `Int` is 32-bit two's complement, `(hi << 16) | lo` already yields
/// the correct signed value for both positive and negative inputs.
pub fn int32_fold(hi : Int, lo : Int) -> Int {
(hi << 16) | (lo & 0xFFFF)
}
///|
/// The two words of a 32-bit `int` in the register order they occupy on the
/// wire: the first element goes to the lower register address.
pub fn int32_words(v : Int, order : WordOrder) -> (Int, Int) {
let (hi, lo) = int32_parts(v)
match order {
HighWordLowAddress => (hi, lo)
LowWordLowAddress => (lo, hi)
}
}
///|
/// Rebuild a 32-bit `int` from the two words as transmitted, given their order.
/// The pair is `(lower_address_word, higher_address_word)`.
pub fn int32_fold_words(w0 : Int, w1 : Int, order : WordOrder) -> Int {
let atLowAddr = w0 & 0xFFFF
let atHighAddr = w1 & 0xFFFF
match order {
// With native order the high word sits at the lower address, so `w0` is hi.
HighWordLowAddress => int32_fold(atLowAddr, atHighAddr)
// With swapped order the low word sits at the lower address, so `w1` is hi.
LowWordLowAddress => int32_fold(atHighAddr, atLowAddr)
}
}
///|
/// Encode a 32-bit value into a Modbus byte payload ([hi..lo] per word) given
/// both byte and word order. Returns 4 bytes in wire order, ints in 0..=255.
pub fn encode_int32_bytes(
v : Int,
byteOrder : ByteOrder,
wordOrder : WordOrder,
) -> Array[Int] {
let (wLow, wHigh) = int32_words(v, wordOrder)
let (b0, b1) = uint16_to_bytes(wLow, byteOrder)
let (b2, b3) = uint16_to_bytes(wHigh, byteOrder)
[b0, b1, b2, b3]
}
///|
/// Decode a 4-byte Modbus payload back into a 32-bit `int`.
pub fn decode_int32_bytes(
bytes : Array[Int],
byteOrder : ByteOrder,
wordOrder : WordOrder,
) -> Int {
let b0 = bytes[0] & 0xFF
let b1 = bytes[1] & 0xFF
let b2 = bytes[2] & 0xFF
let b3 = bytes[3] & 0xFF
let wLow = bytes_to_uint16(b0, b1, byteOrder)
let wHigh = bytes_to_uint16(b2, b3, byteOrder)
int32_fold_words(wLow, wHigh, wordOrder)
}
///|
test "uint16 bytes differ under big vs little endian" {
let be = uint16_to_bytes(0x1234, BigEndian)
let le = uint16_to_bytes(0x1234, LittleEndian)
assert_eq(be, (0x12, 0x34))
assert_eq(le, (0x34, 0x12))
}
///|
test "bytes and words round trip" {
assert_eq(bytes_to_uint16(0x12, 0x34, BigEndian), 0x1234)
assert_eq(bytes_to_uint16(0x34, 0x12, LittleEndian), 0x1234)
// The swap of a swap is identity (compared by name, since these types have
// no derived Eq and comparing enums directly triggers a deprecation warning).
assert_eq(byte_order_name(swap_byte_order(BigEndian)), "little-endian")
assert_eq(word_order_name(swap_word_order(LowWordLowAddress)), "hi-lo")
}
///|
test "int16 two's complement maps negative values" {
assert_eq(encode_int16(0), 0)
assert_eq(encode_int16(-1), 0xFFFF)
assert_eq(encode_int16(32767), 0x7FFF)
assert_eq(decode_int16(0xFFFF), -1)
assert_eq(decode_int16(0x8000), -32768)
assert_eq(decode_int16(0x7FFF), 32767)
assert_eq(decode_int16(encode_int16(-249)), -249)
}
///|
test "coil maps to 0 or 1 and decodes any non-zero as on" {
assert_eq(encode_coil(true), 1)
assert_eq(encode_coil(false), 0)
assert_eq(decode_coil(1), true)
assert_eq(decode_coil(0), false)
assert_eq(decode_coil(0x8000), true)
}
///|
test "int32_parts separates high and low words" {
assert_eq(int32_parts(0x12345678), (0x1234, 0x5678))
assert_eq(int32_fold(0x1234, 0x5678), 0x12345678)
// Negative values keep the two's-complement high word.
let (hi, lo) = int32_parts(-1)
assert_eq(hi, 0xFFFF)
assert_eq(lo, 0xFFFF)
assert_eq(int32_fold(0xFFFF, 0xFFFF), -1)
}
///|
test "int32_words respects word order" {
assert_eq(int32_words(0x12345678, HighWordLowAddress), (0x1234, 0x5678))
assert_eq(int32_words(0x12345678, LowWordLowAddress), (0x5678, 0x1234))
assert_eq(int32_fold_words(0x1234, 0x5678, HighWordLowAddress), 0x12345678)
assert_eq(int32_fold_words(0x5678, 0x1234, LowWordLowAddress), 0x12345678)
}
///|
test "int32 byte encoding round trips under every endianness" {
let values = [0, 1, -1, 32767, -32768, 0x12345678]
for v in values {
let be = encode_int32_bytes(v, BigEndian, HighWordLowAddress)
assert_eq(decode_int32_bytes(be, BigEndian, HighWordLowAddress), v)
let le = encode_int32_bytes(v, LittleEndian, LowWordLowAddress)
assert_eq(decode_int32_bytes(le, LittleEndian, LowWordLowAddress), v)
}
}
///|
test "swapping byte or word order changes the encoded payload" {
let a = encode_int32_bytes(0x12345678, BigEndian, HighWordLowAddress)
let b = encode_int32_bytes(0x12345678, LittleEndian, HighWordLowAddress)
let c = encode_int32_bytes(0x12345678, BigEndian, LowWordLowAddress)
assert_eq(a[0], 0x12)
assert_eq(c[0], 0x56) // low word moved to the lower address
let mut differ = 0
for k = 0; k < a.length(); k = k + 1 {
if a[k] != b[k] {
differ = differ + 1
}
}
assert_eq(differ > 0, true)
}
// ---------------------------------------------------------------------------
// Floating point.
//
// MoonBit does not expose a Double <-> Int64 bit-cast primitive, so these
// functions build and tear down the IEEE-754 pattern with plain arithmetic:
// - encode: normalise the magnitude into [1, 2), then scale the mantissa
// into a 52/23-bit integer (via the exact `Double.to_int64()` truncation).
// - decode: rebuild the value as `(2^52 | mant) * 2^(E - 1075)`, which is an
// exact integer-times-power-of-two that reproduces the original double.
//
// The APIs use a fixed big-endian word order (most-significant word first).
// Per-word byte order is supported through the *bytes helpers, reusing
// `uint16_to_bytes` / `bytes_to_uint16`.
// ---------------------------------------------------------------------------
///|
/// The 16-bit WORD PACK that a double occupies, high word first.
fn split_words64(b : Int64) -> (Int, Int, Int, Int) {
let w0 = ((b >> 48) & 0xFFFFL).to_int()
let w1 = ((b >> 32) & 0xFFFFL).to_int()
let w2 = ((b >> 16) & 0xFFFFL).to_int()
let w3 = (b & 0xFFFFL).to_int()
(w0, w1, w2, w3)
}
///|
/// The reverse of `split_words64`.
fn compose_words64(w0 : Int, w1 : Int, w2 : Int, w3 : Int) -> Int64 {
(w0.to_int64() << 48) |
(w1.to_int64() << 32) |
(w2.to_int64() << 16) |
w3.to_int64()
}
///|
/// IEEE-754 double-precision bits for `v`. This is an exact bit-preserving
/// reinterpretation, so every pattern (normal, subnormal, ±0, ±Inf, NaN) is
/// represented faithfully.
fn double_bits(v : Double) -> Int64 {
v.reinterpret_as_int64()
}
///|
/// Rebuild the exact `Double` from its IEEE-754 bit pattern.
fn double_from_bits(b : Int64) -> Double {
b.reinterpret_as_double()
}
///|
/// The four 16-bit words (high word first) of a double-precision value.
pub fn float64_words(v : Double) -> (Int, Int, Int, Int) {
split_words64(double_bits(v))
}
///|
/// Rebuild a double-precision value from its four words (high word first).
pub fn float64_from_words(w0 : Int, w1 : Int, w2 : Int, w3 : Int) -> Double {
double_from_bits(compose_words64(w0, w1, w2, w3))
}
///|
/// The eight bytes (in wire order for `byteOrder`) of a double value, walking
/// four words from the most-significant word first.
pub fn float64_bytes(v : Double, byteOrder : ByteOrder) -> Array[Int] {
let (w0, w1, w2, w3) = float64_words(v)
let (h0, l0) = uint16_to_bytes(w0, byteOrder)
let (h1, l1) = uint16_to_bytes(w1, byteOrder)
let (h2, l2) = uint16_to_bytes(w2, byteOrder)
let (h3, l3) = uint16_to_bytes(w3, byteOrder)
[h0, l0, h1, l1, h2, l2, h3, l3]
}
///|
/// Rebuild a double value from eight bytes produced by `float64_bytes`.
pub fn float64_from_bytes(bytes : Array[Int], byteOrder : ByteOrder) -> Double {
let w0 = bytes_to_uint16(bytes[0] & 0xFF, bytes[1] & 0xFF, byteOrder)
let w1 = bytes_to_uint16(bytes[2] & 0xFF, bytes[3] & 0xFF, byteOrder)
let w2 = bytes_to_uint16(bytes[4] & 0xFF, bytes[5] & 0xFF, byteOrder)
let w3 = bytes_to_uint16(bytes[6] & 0xFF, bytes[7] & 0xFF, byteOrder)
float64_from_words(w0, w1, w2, w3)
}
///|
/// IEEE-754 single-precision bits for `v` (a `Double`, rounded to float32).
fn float32_bits(v : Double) -> Int {
if v != v {
return 0x7FC00000
}
let neg = if v < 0.0 {
true
} else if v == 0.0 {
1.0 / v < 0.0
} else {
false
}
let g = v.abs()
if g == 0.0 {
return if neg { 0x80000000 } else { 0 }
}
let mut m = g
let mut e2 = 0
if m >= 2.0 {
while m >= 2.0 {
m = m * 0.5
e2 = e2 + 1
}
} else if m < 1.0 {
while m < 1.0 {
m = m * 2.0
e2 = e2 - 1
}
}
let exp_raw = e2 + 127
if exp_raw <= 0 {
let scaled = (g * @math.pow(2.0, 149.0) + 0.5).to_int64().to_int()
let mant = scaled & 0x7FFFFF
let sign = if neg { 0x80000000 } else { 0 }
return sign | mant
}
let frac = m - 1.0
let mut mant = (frac * 8388608.0 + 0.5).to_int64().to_int()
let mut ef = exp_raw
if mant >= 8388608 {
mant = 0
ef = ef + 1
}
let sign = if neg { 0x80000000 } else { 0 }
sign | ((ef << 23) & 0x7F800000) | (mant & 0x7FFFFF)
}
///|
/// Rebuild a single-precision value (as a `Double`) from its 32-bit bits.
fn float32_from_bits(bits : Int) -> Double {
let sign = (bits >> 31) & 1
let exp = (bits >> 23) & 0xFF
let mant = bits & 0x7FFFFF
if exp == 0 {
// Subnormal (or zero): value = mant * 2^-149, no implicit leading one.
let mag = if mant == 0 {
0.0
} else {
mant.to_double() * @math.pow(2.0, -149.0)
}
if sign == 1 {
-mag
} else {
mag
}
} else if exp == 0xFF {
// Special sentinel: all-ones exponent. Mantissa zero is ±Infinity, a
// non-zero mantissa is a NaN (any quiet NaN widens to a double NaN).
if mant == 0 {
if sign == 1 {
0xFFF0000000000000L.reinterpret_as_double()
} else {
0x7FF0000000000000L.reinterpret_as_double()
}
} else {
0x7FF8000000000001L.reinterpret_as_double()
}
} else {
let mag = (8388608 | mant).to_double() *
@math.pow(2.0, (exp - 150).to_double())
if sign == 1 {
-mag
} else {
mag
}
}
}
///|
/// The two 16-bit words (high word first) of a single-precision value.
pub fn float32_words(v : Double) -> (Int, Int) {
let b = float32_bits(v)
let hi = (b >> 16) & 0xFFFF
let lo = b & 0xFFFF
(hi, lo)
}
///|
/// Rebuild a single-precision value from its two words (high word first).
pub fn float32_from_words(hi : Int, lo : Int) -> Double {
float32_from_bits(((hi & 0xFFFF) << 16) | (lo & 0xFFFF))
}
///|
/// The four bytes (in wire order for `byteOrder`) of a single-precision value.
pub fn float32_bytes(v : Double, byteOrder : ByteOrder) -> Array[Int] {
let (hi, lo) = float32_words(v)
let (b0, b1) = uint16_to_bytes(hi, byteOrder)
let (b2, b3) = uint16_to_bytes(lo, byteOrder)
[b0, b1, b2, b3]
}
///|
/// Rebuild a single-precision value from four bytes.
pub fn float32_from_bytes(bytes : Array[Int], byteOrder : ByteOrder) -> Double {
let hi = bytes_to_uint16(bytes[0] & 0xFF, bytes[1] & 0xFF, byteOrder)
let lo = bytes_to_uint16(bytes[2] & 0xFF, bytes[3] & 0xFF, byteOrder)
float32_from_words(hi, lo)
}
///|
test "float64 round trips 1.0 through words" {
let (w0, w1, w2, w3) = float64_words(1.0)
// 1.0 = 0x3FF00000_00000000, so w0=0x3FF0, w1=0, then zeros.
assert_eq(w0, 0x3FF0)
assert_eq(w1, 0)
assert_eq(float64_from_words(w0, w1, w2, w3), 1.0)
}
///|
test "float64 round trips a spread of values" {
let values = [1.0, -1.0, 0.0, -0.0, 3.0, 1234.5, 0.5, -2.25]
for v in values {
let (w0, w1, w2, w3) = float64_words(v)
assert_eq(float64_from_words(w0, w1, w2, w3), v)
let bs = float64_bytes(v, BigEndian)
assert_eq(float64_from_bytes(bs, BigEndian), v)
let ls = float64_bytes(v, LittleEndian)
assert_eq(float64_from_bytes(ls, LittleEndian), v)
}
}
///|
test "float64 bytes differ under big and little endian" {
let be = float64_bytes(1.0, BigEndian)
let le = float64_bytes(1.0, LittleEndian)
assert_eq(be[0], 0x3F)
assert_eq(be[1], 0xF0)
// Little endian flips each word's byte order (low byte first).
assert_eq(le[0], 0xF0)
assert_eq(le[1], 0x3F)
}
///|
test "float32 round trips values that are exactly representable" {
let values = [1.5, -0.25, 3.0, 0.0, -0.0, 1234.0, 0.5]
for v in values {
let (hi, lo) = float32_words(v)
assert_eq(float32_from_words(hi, lo), v)
let be = float32_bytes(v, BigEndian)
assert_eq(float32_from_bytes(be, BigEndian), v)
}
}
///|
test "float32 encodes 1.5 to the expected words" {
// 1.5 = sign 0, exp 127, mantissa 0x400000 => words hi=0x3FC0, lo=0x0000.
let (hi, lo) = float32_words(1.5)
assert_eq(hi, 0x3FC0)
assert_eq(lo, 0)
}
// ---------------------------------------------------------------------------
// Integer boundary tests.
// ---------------------------------------------------------------------------
///|
test "int32 extremes round trip through words and bytes" {
let vals = [2147483647, -2147483648, 0, -1, 1]
for v in vals {
let (hi, lo) = int32_words(v, HighWordLowAddress)
assert_eq(int32_fold_words(hi, lo, HighWordLowAddress), v)
for bo in [BigEndian, LittleEndian] {
for wo in [HighWordLowAddress, LowWordLowAddress] {
let bs = encode_int32_bytes(v, bo, wo)
assert_eq(decode_int32_bytes(bs, bo, wo), v)
}
}
}
}
///|
test "uint32 bit patterns at the upper half of the range" {
// 0x7FFFFFFF.
let (hi1, lo1) = int32_parts(2147483647)
assert_eq(hi1, 0x7FFF)
assert_eq(lo1, 0xFFFF)
// 0x80000000 (bit 31 set) is -2147483648 in two's complement.
let (hi2, lo2) = int32_parts(-2147483648)
assert_eq(hi2, 0x8000)
assert_eq(lo2, 0x0000)
// 0xFFFFFFFF (all bits set) is -1 in two's complement.
let (hi3, lo3) = int32_parts(-1)
assert_eq(hi3, 0xFFFF)
assert_eq(lo3, 0xFFFF)
assert_eq(int32_fold(hi2, lo2), -2147483648)
assert_eq(int32_fold(hi3, lo3), -1)
}
// ---------------------------------------------------------------------------
// Floating-point boundary tests.
// ---------------------------------------------------------------------------
///|
test "float64 edge cases: largest, smallest normal, subnormal, inf, nan" {
let largest = 1.7976931348623157e308
let (l0, l1, l2, l3) = float64_words(largest)
assert_eq(float64_from_words(l0, l1, l2, l3), largest)
let smallest = 4.9406564584124654e-324
let (s0, s1, s2, s3) = float64_words(smallest)
assert_eq(float64_from_words(s0, s1, s2, s3), smallest)
// +Infinity produces the double pattern 0x7FF0 0000 0000 0000.
let (i0, i1, i2, i3) = float64_words(
0x7FF0000000000000L.reinterpret_as_double(),
)
assert_eq(i0, 0x7FF0)
assert_eq(i1, 0)
assert_eq(i2, 0)
assert_eq(i3, 0)
// NaN round trips: re-encoding its words still yields a NaN (self-unequal).
let nan = 0x7FF8000000000001L.reinterpret_as_double()
let (a, b, c, d) = float64_words(nan)
let nan2 = float64_from_words(a, b, c, d)
assert_eq(nan2 != nan2, true)
}
///|
test "float32 edge cases: normal bounds, subnormal, inf, and NaN pattern" {
let hi_normal = 3.4028234663852886e38
let (h0, h1) = float32_words(hi_normal)
assert_eq(float32_from_words(h0, h1), hi_normal)
let lo_normal = 1.1754943508222875e-38
let (n0, n1) = float32_words(lo_normal)
assert_eq(float32_from_words(n0, n1), lo_normal)
// Smallest positive subnormal float32 is 2^-149.
let sub = 1.401298464324817e-45
let (u0, u1) = float32_words(sub)
assert_eq(float32_from_words(u0, u1), sub)
// Decoding the float32 +inf pattern gives a positive infinity.
assert_eq(float32_from_words(0x7F80, 0x0000) > 3.402823466e38, true)
// Decoding a quiet-NaN pattern yields a NaN (self-unequal).
let nan = float32_from_words(0x7FC0, 0x0000)
assert_eq(nan != nan, true)
}