# #decimal(_:) macro

Creating a `Decimal` value from a floating-point literal is imprecise because the literal is routed through `Double` before becoming a `Decimal`.

``````import Foundation

let imprecise: Decimal = 3.333333333
print(imprecise) // prints 3.333333333000000512

let precise = Decimal(string: "3.333333333")!
print(precise) // prints 3.333333333
``````

For this reason, some developers use `Decimal(string:)` when creating a decimal to ensure precision; however, this leads to inefficiency since the string needs to be parsed at runtime.

I propose that we add a new `#decimal` macro which parses a string at compile-time into a Decimal.

``````let precise = #decimal("3.333333333") // non-optional

/* expands to */
let precise = Decimal(_exponent: -9, _length: 1, _isNegative: 0, _isCompact: 2, _reserved: 0, _mantissa: (41301, 50862, 0, 0, 0, 0, 0, 0))

``````
1 Like

Better yet, you can make it take a floating point literal for compile time guaranteed input correctness:

``````let precise = #Decimal(3.333333333)

/* expands to */
let precise = Decimal(string: "3.333333333")!
``````

There was already an accepted proposal to add a `StaticBigInt` for a similar purpose. Seems to me like we'd just need a `StaticBigFloat`, or something like that.

Ideally, the syntax should just let you write:

``````let precise: Decimal = 3.333333333
``````

without the literal being narrowed to a `Double` and losing precision.

11 Likes

Why not have that macro parse the literal at compile-time instead of expanding to the runtime string initialization?

2 Likes

This reflects a limitation of float literals which is tracked by SR-920. The `Decimal` type itself belongs to Foundation, with an uncertain future going forward, so any solution that's specific to that type couldn't be sunk down. Improvements to float literals would benefit existing standard library floating-point types anyway and are sorely needed, and for that reason, a macro wouldn't be the ideal solution.

10 Likes

Yeah sorry, that's what I meant :)

The correct way is indeed to improve existing literal protocols, but a macro sounds like a good idea for contexts where you need to back-deploy... because if it's like `StaticBigInt`, those improvements won't be available when running on older Apple platforms.