Hi, i was wondering why the Decimal swift type didn't have a rounded() function. Relying on casting to NSDecimalNumber for that feels really ugly. Is there something i've missed ?
You don't have to cast, you can use func NSDecimalRound(_:_:_:_:)
. But yes, for some arithmetics you will have to resort to an NSDecimal...
function. I do not know the design reasons though.
This was oversight when introducing the struct type, unfortunately. We've got a Radar tracking this internally (rdar://problem/35857141 for those interested), but if you have a moment do you mind please filing a JIRA?
Falling back to NSDecimalNumber
shouldn't be necessary, and using NSDecimalRound
is quite painful:
var decimal = Decimal(1000.1234)
var rounded = Decimal()
NSDecimalRound(&rounded, &decimal, 2, .bankers) // requires rounded to be initialized, and decimal to be a var
I think ideally we'd add
func rounded(_ scale: Int = 0, _ roundingMode: RoundingMode = .plain) -> Decimal
mutating func round(_ scale: Int = 0, _ roundingMode: RoundingMode = .plain)
Perhaps the more general question is: Why doesn't Decimal
conform to FloatingPoint
?
FloatingPoint
requires IEEE 754 semantics, and Decimal
does not provide them.
The FloatingPoint documentation doesn't mention anything about IEEE 754 upfront. I had to read quite a bit until I found what I guess is the relevant section:
Types that conform to the FloatingPoint protocol provide most basic (clause 5) operations of the IEEE 754 specification. The base, precision, and exponent range are not fixed in any way by this protocol, but it enforces the basic requirements of any IEEE 754 floating-point type.
What are some concrete examples of how Decimal
doesn't comply with the above?
Asking because I saw this: FloatingPoint conformance for Decimal Ā· GitHub
I haven't tested it to see if it works, because I assume it really can't?
Decimal
could conform to FloatingPoint
in the "provides all of the API surface" but not in the "... with the protocol-defined semantics" sense.
There's a whole bunch of ways in which it breaks down, but two name just two concrete ones that come immediately to mind: there's no infinity
and no fused multiply-add operation.
jira filled : [SR-8173] Decimal type doesn't provide round() Ā· Issue #3666 Ā· apple/swift-corelibs-foundation Ā· GitHub
Thanks for filing! Related it to the Radar.
We really need two new protocols that refine Numeric & Comparable
, one for integers that don't necessarily match BinaryInteger
and one for fractional-supporting types that don't necessarily match FloatingPoint
. (Would we need two SignedNumeric
-refined variants too?)
BinaryInteger
and FloatingPoint
would probably refine these new protocols.
What would the semantics of these protocols be, and what stdlib types would conform to them?
If anyone else is interested in solving this in the short term, this is the extension that I used in a project I'm currently working on:
extension Decimal {
mutating func round(_ scale: Int, _ roundingMode: NSDecimalNumber.RoundingMode) {
var localCopy = self
NSDecimalRound(&self, &localCopy, scale, roundingMode)
}
func rounded(_ scale: Int, _ roundingMode: NSDecimalNumber.RoundingMode) -> Decimal {
var result = Decimal()
var localCopy = self
NSDecimalRound(&result, &localCopy, scale, roundingMode)
return result
}
}
Three years later and still not addressed?
Addressing this requires writing a proposal, and since itās Appleās API, itād need to go through an internal review. Feel free to help drive the process forward if youāre interested; I simply donāt have the spare time to do it. Hereās the code:
Almost another three years later and STILL not addressed :D ridiculous