-
Notifications
You must be signed in to change notification settings - Fork 23
Description
Add decimal to standard library
Abstract
Adding a data type that provides support for decimal numbers (base 10 rather than base 2).
Motivation
Many programming languages have built-in support for decimal types and decimal math. This is because when writing programs that support numbers and both originate in base-10 math and are stored in base-10 math, converting to binary floating point number creates unwanted conversion errors between the numbering systems.
The most common types of programs that use decimal:
- financial or banking programs
- scientific or lab-oriented programs
Some examples from other languages:
- C#: https://docs.microsoft.com/en-us/dotnet/api/system.decimal?view=net-5.0
- python: https://docs.python.org/3/library/decimal.html
- PostgreSQL: https://www.postgresql.org/docs/10/datatype-numeric.html (see
decimal)
One of the benefits of adding it to the standard library is possible compiler support as well. This is important for handling source-code literals. Details below.
Description
This would be a single 'decimal.nim' file added to the list of pure libraries that come with the compiler. A new decimal type is introduced and allows decimal storage and manipulation.
Adding this to the standard library creates a common point of reference for other libraries and procedures that need to pass or receive decimal numbers with other libraries.
I recommend that the library store a big decimal number that can meet and conform to a public spec. Specifically, I recommend it meet IEEE 754-2008's 128-bit specification. I'm not suggesting that it store the number in the IEEE spec. Simply that it be designed to support:
- at least 34 digits of precision
- stored significance value
- +/- infinity and nan states
That way, the decimal library could be used to export/import the IEEE spec.
One of the benefits of making it standard is possibly also better handling of decimal literals in source during compilation. For example, using a third party library, the following could be made to work:
var x: decimal = "123.456"but the following could not work:
var x: decimal = 123.456This is because the compiler normally would convert the 123.456 into a floating point number before attempting to assign it. Thus, it introduces a base2-to-base10 conversion problem before the number is even stored.
Four ways this could be handled:
-
the compiler "figures out" that it is trying to convert a sequence of digits for assignment to a decimal and passes in the value as a string despite the lack of quotes.
-
Support for a suffix, similar to the method seen in c#'s
mis used. Thus,123.456mis the same asnewDecimal("123.456"). -
Generic support for number suffixes to be usable generically. So,
123.456mbecomesm"123.456". The decimal library would define a string template or proc form. -
Compiler does nothing new and the decimal library simply fails if you attempt to assign a floating point number to it. In that case, this proposal is strictly a new library for the Nim standard library.
I strongly suggest option 3 as it also opens up possibilities for other uses.
BTW, two third-party decimal libraries of note; both based on the IEEE protocol:
https://github.com/status-im/nim-decimal
https://github.com/JohnAD/decimal128
The second one I wrote myself. Neither are really ready for inclusion in the standard library yet.
This project will take at least a year to complete.
Examples
import decimal
let a: decimal = 4003.250m
assert a.significance == 7
assert a.scale == 3
assert a.toFloat == 4003.25
assert a.toInt == 4003
assert $a == "4003.250"
assert 4003.250m == decimal("4003.250")
assert 4003.250m == decimal("4003250E-3")
assert 4003.250m != decimal("4003.25")Backward incompatibility
There would not be any backward incompatibility issues since decimal numbers are not currently supported by the language or it's standard library.