Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ let current = bestBid.load(ordering: .acquiring)
let nan = FixedPointDecimal.nan
nan.isNaN // true
nan == nan // true (sentinel semantics)
(nan + someValue).isNaN // true (propagates)
nan + someValue // traps (NaN is signalling)
nan.description // "nan"
```

Expand Down Expand Up @@ -301,7 +301,7 @@ bash Fuzz/run.sh debug run

The fuzzer validates invariants across all operations:

- **Arithmetic**: commutativity, NaN propagation, no silent NaN sentinel creation
- **Arithmetic**: commutativity, NaN trapping, no silent NaN sentinel creation
- **Comparisons**: strict total order (exactly one of `<`, `==`, `>`)
- **Conversions**: String, Double, Decimal, Codable round-trips
- **Rounding**: scale-8 identity, no overflow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ let i = Int(somePrice) // 123

## NaN Support

A sentinel-based NaN value propagates through all operations:
NaN is signalling — any arithmetic operation on a NaN value traps immediately:

```swift
let missing = FixedPointDecimal.nan
missing.isNaN // true
(missing + someValue).isNaN // true (propagates)
missing == .nan // true (sentinel semantics)
missing + someValue // traps (precondition failure)
```

## Codable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ This value was chosen because:
NaN uses **sentinel semantics**, not IEEE 754:
- `NaN == NaN` returns `true` (required for `Hashable` and `Comparable` correctness)
- NaN compares less than all non-NaN values (provides a strict total order for sorting)
- Arithmetic with NaN propagates NaN (any operation involving NaN returns NaN)
- Arithmetic with NaN traps (NaN is signalling — any operation involving NaN is a precondition failure)
- `init(_ decimal: Decimal)` maps `Decimal.nan` to `.nan`; `Decimal(.nan)` returns `Decimal.nan`
- `isFinite` returns `false` for NaN, `true` for all other values
- `sign` returns `.plus` for NaN (NaN is excluded from the negative check)
Expand Down
2 changes: 1 addition & 1 deletion Sources/FixedPointDecimal/FixedPointDecimal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ public struct FixedPointDecimal: Sendable, BitwiseCopyable {
/// Follows the swift-numerics `ElementaryFunctions` naming convention.
///
/// Negative exponents compute the reciprocal: `pow(x, -n) == 1 / pow(x, n)`.
/// Returns `.nan` if the base is NaN, or if the result overflows Int64 storage.
/// - Precondition: The base must not be NaN. Traps on overflow.
///
/// ```swift
/// FixedPointDecimal.pow(10, 3) // 1000
Expand Down
Loading