swift-numerics
swift-numerics copied to clipboard
Quick first pass on saturating arithmetic.
Implements adding,subtracting,negating,multiplyingWithSaturation on FixedWidthInteger, which seems like a plausible MVP for saturating arithmetic. Still need to write tests. No attempt to make these map to HW instructions yet.
I gave some consideration to more exotic variants like multiplyingDoublingHighWithSaturation, but those seem like a better fit for a fixed-point type, rather than integer arithmetic primitives.
This is another piece of https://github.com/apple/swift-numerics/issues/10
N.B. I'm not totally set on spelling, but reasonably happy with this. These are pretty niche, so it's ok for them to be wordy. I also experimented with Saturating.add, etc, but I didn't totally love that.
@swift-ci test
@swift-ci test
@swift-ci test
Just throwing out another suggestion:
saturatedAdding(_:)
saturatedSubtracting(_:)
saturatedNegation
saturatedMultiplication(by:)
I think if I went that direction, I would probably do:
Saturated.sum(_:_:)
Saturated.product(_:_:)
Saturated.negation(_:)
This is more in-line with other "modified" ops we've been looking at. I'm not sure what to do with subtraction though; I don't much like Saturated.difference(_:_:), for instance.
@swift-ci test
Saturation is the term of art here, but if you are unfamiliar with the concept, saturation does not immediately indicate a range enforcement (IMO) – and so I was wondering if it would be better to use a different term. BinaryInteger, for example, uses clamping to convey a similar restriction for its init<T>(clamping source: T) where T : BinaryInteger initializer which, I believe, belongs to the same category of saturated arithmetic. I think addingWithClamping et al. conveys the range enforcement quite nicely.
Saturation is the term of art here, but if you are unfamiliar with the concept, saturation does not immediately indicate a range enforcement (IMO) – and so I was wondering if it would be better to use a different term.
I've been pondering this off and on the last few months, and I've settled on sticking with "saturating". It's true that the existing stdlib initializers use (clamping:), but:
- I expect most people who are looking for this functionality to be familiar with the term-of-art "saturating" and to search for that name first. Beyond being the term-of-art, it's much, much more precedented than anything else:
- Wikipedia: https://en.wikipedia.org/wiki/Saturation_arithmetic
- ARM: SQADD.8h ("signed saturating addition of eight half-word integers")
- x86: VPADDUSB ("vector packed addition with unsigned saturation of bytes")
- clang generic vectors: "__builtin_elementwise_add_sat"
- rust: "saturating_add"
- C++ P0543 proposes "add_sat"
- ...
-
The larger group of people who are not already familiar with this style of arithmetic don't know to search for it under any name, but we can document it clearly so that they understand it when they find it, and we teach them the "correct" term that will allow them to find the bindings in other domains in the future.
-
We can reference the
(clamping: Other)inits in the documentation to help experienced users find those.
@swift-ci test
"Clamping" is great for labeling the argument of an initializer ("saturating" wouldn't be nearly as good as we're saturating the range of the result type, not the argument), but I would definitely agree "clamping addition" is just...not the way.
@swift-ci test