You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+45-1Lines changed: 45 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -201,11 +201,55 @@ If Decimal becomes a part of standard JavaScript, it may be used in some built-i
201
201
202
202
More host API interactions are discussed in [#5](https://github.com/tc39/proposal-decimal/issues/5).
203
203
204
+
## Prior Art
205
+
206
+
Adding decimal arithmetic would not be an instance of JS breaking new ground. Many major programming languages have recognized that decimal arithmetic is fundamental enough to include in the standard library, if not as a primitive type.
207
+
208
+
### Decimal Support Across Languages
209
+
210
+
| Language | Type Name | Location | Year Added | Notes |
SQL also has `NUMERIC`/`DECIMAL` as a built-in type, predating many programming languages.
219
+
220
+
Many languages added decimal support 10+ years ago. The IEEE 754-2008 standard for Decimal128 is now 17 years old. (The 2019 edition of IEEE 754 also has decimal arithmetic.)
221
+
Indeed, multiple numeric types are not unusual. Languages ship with integers, floats, *and* decimals. Python even includes both decimals and rationals. The existence of JS's `Number` and `BigInt` doesn't preclude `Decimal`. Moreover, the need for decimal types across many languages reflects a genuine, universal need rather than a niche requirement.
222
+
223
+
### Why JavaScript Lacks Decimal Support
224
+
225
+
JavaScript's origins as a lightweight browser scripting language meant it initially shipped with minimal numeric support (just IEEE 754 binary floats). However, JavaScript's role has fundamentally changed:
226
+
227
+
-**Then (1995)**: Simple form validation and DOM manipulation
There are also money-specific libraries such as [dinero.js](https://www.npmjs.com/package/dinero.js) with about 180K weekly NPM downloads.
241
+
242
+
Each implementation has slightly different semantics, requires coordination across libraries, adds to total bundle size, presumably performs worse than native implementations could, and creates interoperability challenges.
243
+
244
+
Compare this to BigInt: before native support, polyfills and userland big integer libraries had minimal adoption because the *need* was niche. Decimal libraries show massive adoption because the need is universal.
245
+
246
+
Thus, Decimal standardizes existing practice. Developers are already using decimal libraries (millions of downloads/week), converting numbers to "cents" (error-prone, confusing), using `Number` incorrectly (causing bugs). Decimal doesn't ask developers to adopt something new; it offers a better way to do what they're already struggling to do.
247
+
204
248
## Specification and standards
205
249
206
250
Based on feedback from JS developers, engine implementors, and the members of the TC39 committee, we have a concrete proposal. Please see the [spec text](https://github.com/tc39/proposal-decimal/blob/main/spec.emu) ([HTML version](https://github.com/tc39/proposal-decimal/blob/main/spec.emu)). are provided below. You’re encouraged to join the discussion by commenting on the issues linked below or [filing your own](https://github.com/tc39/proposal-decimal/issues/new).
207
251
208
-
We will use the **Decimal128** data model for JavaScript decimals. Decimal128 is not a new standard; it was added to the IEEE 754 floating-point arithmetic standard in 2008. It represents the culmination of decades of research, both theoretical and practical, on decimal floating-point numbers. Values in the Decimal128 universe take up 128 bits. In this representation, up to 34 significant digits (that is, decimal digits) can be stored, with an exponent (power of ten) of +/- 6143.
252
+
We will use the **Decimal128** data model for JavaScript decimals. Decimal128 is not a new standard; it was added to the IEEE 754 floating-point arithmetic standard in 2008 (and is present in the 2019 edition of IEEE 754, which JS normatively depends upon). It represents the culmination of decades of research on decimal floating-point numbers. Values in the Decimal128 universe take up 128 bits. In this representation, up to 34 significant digits (that is, decimal digits) can be stored, with an exponent (power of ten) of +/- 6143.
209
253
210
254
In addition to proposing a new `Decimal` class, we propose a `Decimal.Amount` class for storing a Decimal number together with a precision. The `Decimal.Amount` class is important mainly for string formatting purposes, where one desires to have a notion of a number that “knows” how precise it is. We do not intend to support arithmetic on `Decimal.Amount` values, the thinking being that `Decimal` already supports arithmetic.
Copy file name to clipboardExpand all lines: docs/cookbook.md
+147-6Lines changed: 147 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,16 +20,150 @@ const total = price.multiply(quantity);
20
20
console.log(total.toString()); // => "59.97"
21
21
```
22
22
23
+
## Prior Art: Decimal Arithmetic in Other Languages
24
+
25
+
The patterns demonstrated in this cookbook are not unique to JavaScript - they reflect well-established practices across programming languages. This section shows how other languages handle the same decimal arithmetic challenges, demonstrating that native decimal support is standard across the industry.
26
+
27
+
### Python
28
+
29
+
Python includes the `decimal` module in its standard library (since 2003):
30
+
31
+
```python
32
+
from decimal import Decimal
33
+
34
+
# Financial calculations
35
+
price = Decimal("19.99")
36
+
quantity = Decimal("3")
37
+
tax_rate = Decimal("0.0825")
38
+
39
+
subtotal = price * quantity
40
+
tax = subtotal * tax_rate
41
+
total = subtotal + tax
42
+
43
+
print(f"${total:.2f}") # => "$64.62"
44
+
```
45
+
46
+
Python's `Decimal` is widely used in web frameworks like Django and Flask for handling monetary values. The Django ORM includes a `DecimalField` specifically for financial data.
47
+
48
+
### Java
49
+
50
+
Java's `BigDecimal` (in the standard library since 1998) is ubiquitous in enterprise applications:
51
+
52
+
```java
53
+
importjava.math.BigDecimal;
54
+
importjava.math.RoundingMode;
55
+
56
+
BigDecimal price =newBigDecimal("19.99");
57
+
BigDecimal quantity =newBigDecimal("3");
58
+
BigDecimal taxRate =newBigDecimal("0.0825");
59
+
60
+
BigDecimal subtotal = price.multiply(quantity);
61
+
BigDecimal tax = subtotal.multiply(taxRate);
62
+
BigDecimal total = subtotal.add(tax);
63
+
64
+
// Round to 2 decimal places
65
+
total = total.setScale(2, RoundingMode.HALF_UP);
66
+
System.out.println(total); // => "64.62"
67
+
```
68
+
69
+
`BigDecimal` is the standard approach for financial applications in the Java ecosystem, including frameworks like Spring and Hibernate.
70
+
71
+
### C\#
72
+
73
+
C# includes `decimal` as a primitive type (since 2000), giving it first-class language support:
74
+
75
+
```csharp
76
+
decimalprice=19.99m;
77
+
decimalquantity=3m;
78
+
decimaltaxRate=0.0825m;
79
+
80
+
decimalsubtotal=price*quantity;
81
+
decimaltax=subtotal*taxRate;
82
+
decimaltotal=subtotal+tax;
83
+
84
+
Console.WriteLine($"${total:F2}"); // => "$64.92"
85
+
```
86
+
87
+
### Ruby
88
+
89
+
Ruby includes `BigDecimal` in its standard library:
90
+
91
+
```ruby
92
+
require'bigdecimal'
93
+
94
+
price =BigDecimal("19.99")
95
+
quantity =BigDecimal("3")
96
+
tax_rate =BigDecimal("0.0825")
97
+
98
+
subtotal = price * quantity
99
+
tax = subtotal * tax_rate
100
+
total = subtotal + tax
101
+
102
+
puts"$%.2f"% total # => "$64.92"
103
+
```
104
+
105
+
Ruby on Rails uses [`BigDecimal`](https://ruby-doc.org/3.4.1/exts/json/BigDecimal.html) for handling database `decimal` columns by default, making it the standard approach for money in Rails applications.
106
+
107
+
### Swift
108
+
109
+
Swift's Foundation framework includes [`Decimal`](https://developer.apple.com/documentation/foundation/decimal) (formerly [`NSDecimalNumber`](https://developer.apple.com/documentation/foundation/nsdecimalnumber)):
110
+
111
+
```swift
112
+
importFoundation
113
+
114
+
let price =Decimal(string: "19.99")!
115
+
let quantity =Decimal(string: "3")!
116
+
let taxRate =Decimal(string: "0.0825")!
117
+
118
+
let subtotal = price * quantity
119
+
let tax = subtotal * taxRate
120
+
let total = subtotal + tax
121
+
122
+
let formatter =NumberFormatter()
123
+
formatter.numberStyle= .currency
124
+
print(formatter.string(from: total as NSDecimalNumber)!) // => "$64.62"
125
+
```
126
+
127
+
Swift's `Decimal` is the recommended type for financial calculations in iOS and macOS applications.
128
+
129
+
### SQL
130
+
131
+
Most SQL databases treat decimal arithmetic as fundamental:
132
+
133
+
```sql
134
+
SELECT
135
+
price,
136
+
quantity,
137
+
price * quantity AS subtotal,
138
+
(price * quantity) *0.0825AS tax,
139
+
(price * quantity) *1.0825AS total
140
+
FROM products
141
+
WHERE id =1;
142
+
```
143
+
144
+
Database `NUMERIC` and `DECIMAL` types provide exact decimal arithmetic. When JavaScript applications query these values, they currently must receive them as strings (or as `Number`s, which may lose precision from the get-go) that are then converted to `Number` (which also loses precision), or use a userland decimal library.
145
+
146
+
Native JavaScript Decimal would allow seamless interchange with database decimal types.
147
+
148
+
### Why This Matters for JavaScript
149
+
150
+
JavaScript forces developers to choose between:
151
+
152
+
- Binary floats (precision errors, bugs, non-trivial knowledge of binary float problems and some countermeasures that may not always work)
The patterns in this cookbook reflect industry-standard practices that JavaScript developers should be able to use natively, just as developers in other major languages can.
157
+
23
158
## Common Patterns
24
159
25
160
This section demonstrates common patterns and best practices when working with Decimal.
26
161
27
162
### Working with Monetary Values
28
163
29
-
Always create Decimal values from strings to ensure exact representation:
164
+
Create Decimal values from strings to ensure exact representation:
(However, there are some digit strings that Number can handle just fine, namely those with more than 34 significant digits that have compact representations as sums of powers of two.)
323
+
However, there are some digit strings that Number can handle just fine, namely those with more than 34 significant digits that have compact representations as sums of powers of two.
0 commit comments