| Question | Choice here | Where |
|---|---|---|
Device value for a / 0 | sign(a) * max, 0 for 0 / 0 (spec section 12, proposed) | _reference.div |
Device value for sqrt(a < 0) | 0 (proposed) | _reference.sqrt |
| Rounding of div and sqrt | truncate toward zero, matching mul (proposed) | _reference.div, _reference.sqrt |
fma event when the product underflows and the sum overflows | overflow (what the final value shows) | _reference.fma |
x ** 0 | overflow (1 is not representable); x ** k, k >= 1, is the left-to-right mul chain; negative / non-integer k is unsupported | _scalar.__pow__ |
under="raise" | raises SFUnderflowError; the spec only names the warning | _errors.py |
over/divide/invalid = "warn" | SFOverflowWarning, SFZeroDivisionWarning, SFInvalidWarning (spec names none) | _errors.py |
Foreign operator operands (x + "0.25", None - x) | SFTypeError (a TypeError subclass), per the catalogue. The Python protocol (NotImplemented) is used only for a non-builtin type that itself defines the matching reflected operator, so third-party numeric types still interoperate | _scalar._reject |
| Exponent / code / bits types | anything operator.index accepts (Python int, NumPy ints, __index__); bool rejected | _scalar._as_index |
x ** n cost | the mul chain stops at the first 0, so cost is bounded by the steps to reach 0 (at most 2^(N-1) - 1, for x = max), not by n | _reference.pow_int |
| NaN comparisons | like IEEE: == False, != True, ordering False | _scalar._cmp_value |
hash(x) | hash(x.exact), so sf.sf16(0.5) == 0.5 and the hashes agree; values are usable as dict keys next to floats | _scalar.__hash__ |
| Strings | constructor only (sf.sf16("0.1") is the exact decimal 1/10); never an operator literal | _reference.to_exact, _scalar._coerce |
sf.where | scalar x if c else y; both branches are evaluated by Python before the call | _functions.where |
Design decisions
Semantics not fixed by the spec
Decision log: semantics not fixed by the spec