Skip to content

Add decimal to standard library #308

@JohnAD

Description

@JohnAD

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:

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.456

This 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:

  1. 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.

  2. Support for a suffix, similar to the method seen in c#'s m is used. Thus, 123.456m is the same as newDecimal("123.456").

  3. Generic support for number suffixes to be usable generically. So, 123.456m becomes m"123.456". The decimal library would define a string template or proc for m.

  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions