# Why does Swift not support rational numbers?

There is no support for rational numbers. What is the reason for this?

It would be really nice to have a built-in type for them. Then, it would be possible to write code for very accurate linear transformations, without worrying about the floating point errors when computing inverse transformations.

For example:

``````struct RationalNumber {
typealias NaturalNumber = Uint

let numerator  : NaturalNumber
let denominator: NaturalNumber
let negative   : Bool

init (numerator: NaturalNumber, negative: Bool = false) {
self.init (numerator: numerator, denominator: 1, negative: negative)
}

init (numerator: NaturalNumber, denominator: NaturalNumber, negative: Bool = false) {
self.numerator   = numerator
self.denominator = denominator
self.negative    = negative
}

func add      (_ u: Self) -> Self
func subtract (_ u: Self) -> Self
func multiply (_ u: Self) -> Self
func divide   (_ u: Self) -> Self
}
``````

There are third-party libraries out there, but it would be nice to have a built-in type for this.

What do you think?

It has come up a few times before.

If the use-cases really are so limited, it is probably more appropriate to encourage people to use a package (perhaps `swift-numerics`, or one of the other third-party libraries you mention) rather than adding these to the standard library.

7 Likes

i am not sure if the first two observations support the conclusion here. in a lot of financial applications, there are formulas that must be applied in exact rational form, but the operation depth is fixed such that the implementation does not â€śoverflow immediatelyâ€ť, although the number of bits needed to represent the result may be very large, larger than can fit into a `Int64`.

in the end, we must always round the result such that customers are not transacting in increments of dust, but it is incorrect to say it is â€śalways strictly better to use floating-pointâ€ť. sometimes the rounding is decimal-based, sometimes it is contract-defined, and sometimes it is designed simply to rob people of their dust (way more common than you think, because itâ€™s almost impossible to notice, and usually dwarfed by explicit fees anyway.) but it is very, very rarely performed using floating-point arithmetic.

there are a lot of reasons for this, a few of which i can think off the top of my head:

• business-type people tend to have a hard time understanding floating point,
• contracts are usually defined using ratios, and executing them with floating point opens up a small but non-trivial possibility of major headaches down the road. (but iâ€™ve personally never witnessed anyone get sued over it, because the amounts in dispute are usually quite small. and truth be told, there are a lot of shady things being done to dust on purpose anyway.)
• floating point transactions are really hard to audit, because of scale invariance. this doesnâ€™t always involve wrongdoing, a lot of times people just make small mistakes implementing things, and having a large error tolerance to account for floating point error makes it harder to catch these kinds of bugs.

but i think the first of those reasons is probably by far the most important.

the most commonly-occurring denominators for these kinds of rational parameters are multiples of 10, so this tends to get boxed into a â€śdecimal problemâ€ť. but iâ€™ve also seen denominators like 24, 60, etc. compounded interest is weird.

1 Like

I believe OP actually meant "fixed" point math hence the usage of 32/64 bit UInt for both numerator and denominator in the leading example:

``````typealias NaturalNumber = Uint
let numerator  : NaturalNumber
let denominator: NaturalNumber
``````

I would welcome first class support for Fixed numbers. Don't do finance, but hate when I see floating point gotchas in graphics, e.g. rect math acting weirdly because of this:

``````let a = 100.33333333333333333333333
let b = a + 100
let c = b - 100
assert(a == c) // Assertion failed
``````
1 Like

It also doesn't help that `Decimal` still has known UX and parsing issues. Namely, only ever roundtrip through `String`, do not parse directly from things like JSON numbers. Interactions with `NSNumber` and `NSDecimalNumber` can be tricky.

1 Like