# Decimal has no rounded()

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 ?

2 Likes

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
``````

``````func rounded(_ scale: Int = 0, _ roundingMode: RoundingMode = .plain) -> Decimal
mutating func round(_ scale: Int = 0, _ roundingMode: RoundingMode = .plain)
``````
9 Likes

Perhaps the more general question is: Why doesn't `Decimal` conform to `FloatingPoint`?

2 Likes

`FloatingPoint` requires IEEE 754 semantics, and `Decimal` does not provide them.

5 Likes

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: https://gist.github.com/natecook1000/27d31d73315ffc2c80a7b4efc5788bd0
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.

10 Likes

jira filled : https://bugs.swift.org/browse/SR-8173

2 Likes

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
}
}
``````
10 Likes

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:

1 Like