@fable-org/fable-library-js 2.8.1 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Async.js +209 -23
- package/AsyncBuilder.js +19 -4
- package/CHANGELOG.md +33 -1
- package/Decimal.js +100 -11
- package/Encoding.js +23 -16
- package/MailboxProcessor.js +4 -0
- package/Stopwatch.js +65 -0
- package/String.js +4 -0
- package/Task.js +22 -0
- package/big.d.ts +1 -0
- package/lib/big.js +113 -70
- package/package.json +1 -1
package/Async.js
CHANGED
|
@@ -2,8 +2,8 @@ import { OperationCanceledException, Trampoline } from "./AsyncBuilder.js";
|
|
|
2
2
|
import { CancellationToken } from "./AsyncBuilder.js";
|
|
3
3
|
import { protectedCont, protectedBind, protectedReturn } from "./AsyncBuilder.js";
|
|
4
4
|
import { Choice_makeChoice1Of2, Choice_makeChoice2Of2 } from "./Choice.js";
|
|
5
|
-
import { TimeoutException_$ctor } from "./System.js";
|
|
6
|
-
import { Exception } from "./Util.js";
|
|
5
|
+
import { ArgumentException_$ctor_Z384F8060, InvalidOperationException_$ctor_Z721C83C5, TimeoutException_$ctor } from "./System.js";
|
|
6
|
+
import { Exception, ensureErrorOrException } from "./Util.js";
|
|
7
7
|
function emptyContinuation(_x) {
|
|
8
8
|
// NOP
|
|
9
9
|
}
|
|
@@ -44,27 +44,43 @@ export function throwIfCancellationRequested(token) {
|
|
|
44
44
|
throw new Exception("Operation is cancelled");
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
// The parent keeps the listener until unlink is called
|
|
48
|
+
function createLinkedToken(parent) {
|
|
49
|
+
const token = new CancellationToken();
|
|
50
|
+
const id = parent.addListener(() => token.cancel());
|
|
51
|
+
return [token, () => { parent.removeListener(id); }];
|
|
52
|
+
}
|
|
47
53
|
export function startChild(computation, ms) {
|
|
48
54
|
return protectedCont((ctx) => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
const timeout = ms == null || ms === -1 ? undefined : ms;
|
|
56
|
+
const [childToken, unlink] = timeout === undefined
|
|
57
|
+
? [ctx.cancelToken, () => { }]
|
|
58
|
+
: createLinkedToken(ctx.cancelToken);
|
|
59
|
+
const promise = startAsPromise(computation, childToken);
|
|
60
|
+
let settled = false;
|
|
61
|
+
const onSettled = () => { settled = true; unlink(); };
|
|
62
|
+
// Without a rejection handler an unawaited child's failure is an unhandled rejection
|
|
63
|
+
promise.then(onSettled, onSettled);
|
|
64
|
+
// Like .NET, the timeout only runs while the result is awaited, not from the start of the child
|
|
65
|
+
const awaitResult = () => timeout === undefined || settled ? promise : new Promise((resolve, reject) => {
|
|
66
|
+
const timeoutId = setTimeout(() => {
|
|
67
|
+
// .NET doesn't cancel the child when the timeout is 0
|
|
68
|
+
if (timeout !== 0) {
|
|
69
|
+
try {
|
|
70
|
+
childToken.cancel();
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
reject(error);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
reject(TimeoutException_$ctor());
|
|
78
|
+
}, timeout);
|
|
79
|
+
promise.then(value => { clearTimeout(timeoutId); resolve(value); }, error => { clearTimeout(timeoutId); reject(error); });
|
|
80
|
+
});
|
|
65
81
|
// JS Promises are hot, computation has already started
|
|
66
82
|
// but we delay returning the result
|
|
67
|
-
protectedReturn(awaitPromise(
|
|
83
|
+
protectedReturn(protectedCont((awaitCtx) => awaitPromise(awaitResult())(awaitCtx)))(ctx);
|
|
68
84
|
});
|
|
69
85
|
}
|
|
70
86
|
export function awaitPromise(p) {
|
|
@@ -107,15 +123,179 @@ export function catchAsync(work) {
|
|
|
107
123
|
});
|
|
108
124
|
});
|
|
109
125
|
}
|
|
126
|
+
export function tryCancelled(computation, compensation) {
|
|
127
|
+
return (ctx) => {
|
|
128
|
+
// invariant: install the handler without adding a cancellation checkpoint, including for nested handlers
|
|
129
|
+
computation({
|
|
130
|
+
...ctx,
|
|
131
|
+
onCancel: (error) => {
|
|
132
|
+
// decision: preserve the original cancellation even when compensation throws, matching .NET
|
|
133
|
+
try {
|
|
134
|
+
compensation(error);
|
|
135
|
+
}
|
|
136
|
+
catch { /* Cancellation takes precedence. */ }
|
|
137
|
+
if (ctx.trampoline.incrementAndCheck()) {
|
|
138
|
+
ctx.trampoline.hijack(() => ctx.onCancel(error));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
ctx.onCancel(error);
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
}
|
|
110
147
|
export function fromContinuations(f) {
|
|
111
|
-
return
|
|
148
|
+
return (ctx) => {
|
|
149
|
+
let settled = false;
|
|
150
|
+
const claim = () => {
|
|
151
|
+
if (settled) {
|
|
152
|
+
throw InvalidOperationException_$ctor_Z721C83C5("A continuation was invoked more than once");
|
|
153
|
+
}
|
|
154
|
+
settled = true;
|
|
155
|
+
};
|
|
156
|
+
const success = (x) => { claim(); ctx.onSuccess(x); };
|
|
157
|
+
const error = (x) => { claim(); ctx.onError(x); };
|
|
158
|
+
const cancelled = (x) => { claim(); ctx.onCancel(x); };
|
|
159
|
+
protectedCont(() => f([success, error, cancelled]))({
|
|
160
|
+
onSuccess: success,
|
|
161
|
+
onError: (x) => { if (settled) {
|
|
162
|
+
throw x;
|
|
163
|
+
} error(x); },
|
|
164
|
+
onCancel: cancelled,
|
|
165
|
+
cancelToken: ctx.cancelToken,
|
|
166
|
+
trampoline: ctx.trampoline,
|
|
167
|
+
});
|
|
168
|
+
};
|
|
112
169
|
}
|
|
113
170
|
export function ignore(computation) {
|
|
114
171
|
return protectedBind(computation, (_x) => protectedReturn(void 0));
|
|
115
172
|
}
|
|
116
|
-
export function parallel(computations) {
|
|
117
|
-
|
|
118
|
-
|
|
173
|
+
export function parallel(computations, maxDegreeOfParallelism) {
|
|
174
|
+
if (maxDegreeOfParallelism != null && maxDegreeOfParallelism < 1) {
|
|
175
|
+
throw ArgumentException_$ctor_Z384F8060(`maxDegreeOfParallelism must be positive, was ${maxDegreeOfParallelism}`, "maxDegreeOfParallelism");
|
|
176
|
+
}
|
|
177
|
+
return protectedCont((ctx) => awaitPromise(runParallel(Array.from(computations), maxDegreeOfParallelism, ctx.cancelToken))(ctx));
|
|
178
|
+
}
|
|
179
|
+
function runParallel(computations, limit, parentToken) {
|
|
180
|
+
return new Promise((resolve, reject) => {
|
|
181
|
+
const count = computations.length;
|
|
182
|
+
const results = new Array(count);
|
|
183
|
+
const [token, unlink] = createLinkedToken(parentToken);
|
|
184
|
+
let next = 0;
|
|
185
|
+
let running = 0;
|
|
186
|
+
let failed = false;
|
|
187
|
+
let failure;
|
|
188
|
+
const startNext = () => {
|
|
189
|
+
const i = next++;
|
|
190
|
+
running++;
|
|
191
|
+
startAsPromise(computations[i], token)
|
|
192
|
+
.then((x) => { results[i] = x; }, (err) => {
|
|
193
|
+
if (!failed) {
|
|
194
|
+
failed = true;
|
|
195
|
+
failure = err;
|
|
196
|
+
try {
|
|
197
|
+
token.cancel();
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
failure = error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
.then(() => {
|
|
205
|
+
running--;
|
|
206
|
+
if (!failed && next < count) {
|
|
207
|
+
startNext();
|
|
208
|
+
}
|
|
209
|
+
else if (running === 0) {
|
|
210
|
+
unlink();
|
|
211
|
+
if (failed) {
|
|
212
|
+
reject(failure);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
resolve(results);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
if (count === 0) {
|
|
221
|
+
unlink();
|
|
222
|
+
resolve(results);
|
|
223
|
+
}
|
|
224
|
+
const initial = Math.min(limit ?? count, count);
|
|
225
|
+
while (next < initial) {
|
|
226
|
+
startNext();
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
export function choice(computations) {
|
|
231
|
+
return protectedCont((ctx) => {
|
|
232
|
+
const works = Array.from(computations);
|
|
233
|
+
let remaining = works.length;
|
|
234
|
+
if (remaining === 0) {
|
|
235
|
+
ctx.onSuccess(undefined);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const [token, unlink] = createLinkedToken(ctx.cancelToken);
|
|
239
|
+
let done = false;
|
|
240
|
+
const finish = (report) => {
|
|
241
|
+
if (done) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
done = true;
|
|
245
|
+
unlink();
|
|
246
|
+
try {
|
|
247
|
+
token.cancel();
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
ctx.onError(ensureErrorOrException(error));
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
report();
|
|
254
|
+
};
|
|
255
|
+
for (const work of works) {
|
|
256
|
+
startWithContinuations(work, (x) => {
|
|
257
|
+
if (x != null) {
|
|
258
|
+
finish(() => ctx.onSuccess(x));
|
|
259
|
+
}
|
|
260
|
+
else if (--remaining === 0) {
|
|
261
|
+
finish(() => ctx.onSuccess(undefined));
|
|
262
|
+
}
|
|
263
|
+
}, (err) => finish(() => ctx.onError(err)), (err) => finish(() => ctx.onCancel(err)), token);
|
|
264
|
+
if (done) {
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
export function onCancel(interruption) {
|
|
271
|
+
return protectedCont((ctx) => {
|
|
272
|
+
const token = ctx.cancelToken;
|
|
273
|
+
let interrupted = false;
|
|
274
|
+
const interrupt = () => {
|
|
275
|
+
if (!interrupted) {
|
|
276
|
+
interrupted = true;
|
|
277
|
+
try {
|
|
278
|
+
interruption();
|
|
279
|
+
}
|
|
280
|
+
catch { /* Ignored, like .NET Async.OnCancel */ }
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
const id = token.addListener(interrupt);
|
|
284
|
+
let disposed = false;
|
|
285
|
+
ctx.onSuccess({
|
|
286
|
+
Dispose() {
|
|
287
|
+
if (disposed) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
disposed = true;
|
|
291
|
+
token.removeListener(id);
|
|
292
|
+
// With use! Dispose runs inside cancel() before this listener gets its turn
|
|
293
|
+
if (token.isCancelled) {
|
|
294
|
+
interrupt();
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
});
|
|
119
299
|
}
|
|
120
300
|
export function sequential(computations) {
|
|
121
301
|
function _sequential(computations, cancelToken) {
|
|
@@ -175,3 +355,9 @@ export function startWithContinuations(computation, continuation, exceptionConti
|
|
|
175
355
|
export function startAsPromise(computation, cancellationToken) {
|
|
176
356
|
return new Promise((resolve, reject) => startWithContinuations(computation, resolve, reject, reject, cancellationToken ? cancellationToken : defaultCancellationToken));
|
|
177
357
|
}
|
|
358
|
+
export function startAsTask(computation, _taskCreationOptions, cancellationToken) {
|
|
359
|
+
return startAsPromise(computation, cancellationToken);
|
|
360
|
+
}
|
|
361
|
+
export function startImmediateAsTask(computation, cancellationToken) {
|
|
362
|
+
return startAsPromise(computation, cancellationToken);
|
|
363
|
+
}
|
package/AsyncBuilder.js
CHANGED
|
@@ -174,9 +174,15 @@ export class AsyncBuilder {
|
|
|
174
174
|
return computation;
|
|
175
175
|
}
|
|
176
176
|
TryFinally(computation, compensation) {
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
// The cancellation check in protectedCont must see the cleanup continuations
|
|
178
|
+
return (ctx) => {
|
|
179
|
+
let settled = false;
|
|
180
|
+
protectedCont(computation)({
|
|
179
181
|
onSuccess: (x) => {
|
|
182
|
+
if (settled) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
settled = true;
|
|
180
186
|
try {
|
|
181
187
|
compensation();
|
|
182
188
|
}
|
|
@@ -187,6 +193,10 @@ export class AsyncBuilder {
|
|
|
187
193
|
ctx.onSuccess(x);
|
|
188
194
|
},
|
|
189
195
|
onError: (x) => {
|
|
196
|
+
if (settled) {
|
|
197
|
+
throw x;
|
|
198
|
+
}
|
|
199
|
+
settled = true;
|
|
190
200
|
try {
|
|
191
201
|
compensation();
|
|
192
202
|
}
|
|
@@ -197,6 +207,10 @@ export class AsyncBuilder {
|
|
|
197
207
|
ctx.onError(x);
|
|
198
208
|
},
|
|
199
209
|
onCancel: (x) => {
|
|
210
|
+
if (settled) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
settled = true;
|
|
200
214
|
// decision: cancellation remains terminal when compensation throws, matching .NET Async.TryFinally
|
|
201
215
|
try {
|
|
202
216
|
compensation();
|
|
@@ -207,7 +221,7 @@ export class AsyncBuilder {
|
|
|
207
221
|
cancelToken: ctx.cancelToken,
|
|
208
222
|
trampoline: ctx.trampoline,
|
|
209
223
|
});
|
|
210
|
-
}
|
|
224
|
+
};
|
|
211
225
|
}
|
|
212
226
|
TryWith(computation, catchHandler) {
|
|
213
227
|
return protectedCont((ctx) => {
|
|
@@ -232,7 +246,8 @@ export class AsyncBuilder {
|
|
|
232
246
|
});
|
|
233
247
|
}
|
|
234
248
|
Using(resource, binder) {
|
|
235
|
-
|
|
249
|
+
// Without Delay the binder runs before TryFinally installs Dispose
|
|
250
|
+
return this.TryFinally(this.Delay(() => binder(resource)), () => resource.Dispose());
|
|
236
251
|
}
|
|
237
252
|
While(guard, computation) {
|
|
238
253
|
if (guard()) {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
last_commit_released:
|
|
2
|
+
last_commit_released: 2098f64a25e96385306ef19ed8c289f3b6c84db9
|
|
3
3
|
updaters:
|
|
4
4
|
- package.json:
|
|
5
5
|
file: package.json
|
|
@@ -15,6 +15,38 @@ All notable changes to this project will be documented in this file.
|
|
|
15
15
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
16
16
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
17
17
|
|
|
18
|
+
## 2.10.0 - 2026-10-22
|
|
19
|
+
|
|
20
|
+
### 🚀 Features
|
|
21
|
+
|
|
22
|
+
* *(js/ts)* Support System.Diagnostics.Stopwatch (#5100) ([eb68225f](https://github.com/fable-compiler/Fable/commit/eb68225ff74d1b455765d99998faa6fd3be32383))
|
|
23
|
+
|
|
24
|
+
### 🐞 Bug Fixes
|
|
25
|
+
|
|
26
|
+
* *(js/ts)* Round decimals below 0.1 correctly ([fca4c408](https://github.com/fable-compiler/Fable/commit/fca4c408a64e33c58293f12869975e5b61bcb96a))
|
|
27
|
+
* *(js/ts)* Keep decimal zero scale without leading zeros ([3076b45a](https://github.com/fable-compiler/Fable/commit/3076b45acacf39b8c99ec57025560ad355ab74db))
|
|
28
|
+
* *(js/ts)* Hash decimals by value in collections ([32a69e0d](https://github.com/fable-compiler/Fable/commit/32a69e0d00f567c9a838307e9ed51b3b1d519473))
|
|
29
|
+
* *(js/ts)* Keep .NET decimal scale through arithmetic (#5126) ([bdf0a6c8](https://github.com/fable-compiler/Fable/commit/bdf0a6c8cb56151a5431b5e3703f7ee165b26dba))
|
|
30
|
+
* *(js/ts)* Accept decimal integers up to 2^96 ([c9feb339](https://github.com/fable-compiler/Fable/commit/c9feb339fb8a4e98bebf17b3facdc42ecd22d628))
|
|
31
|
+
* *(js/ts)* Align decimal conversion, parsing and G format ([6430cdac](https://github.com/fable-compiler/Fable/commit/6430cdacec34e6327434af649eb0c9427d65608c))
|
|
32
|
+
* *(js/ts)* Add missing Async and Task members, cancel timed-out StartChild, bind Async in task { } (#5097) ([d063630d](https://github.com/fable-compiler/Fable/commit/d063630d58d62db21603d45a6bf54b172378c66e))
|
|
33
|
+
* *(js/ts)* Respect maxDegreeOfParallelism and cancel on failure in Async.Parallel (#5098) ([5de3271d](https://github.com/fable-compiler/Fable/commit/5de3271d8b47f1752c4e74c010e4314cf40bbcbe))
|
|
34
|
+
|
|
35
|
+
<strong><small>[View changes on Github](https://github.com/fable-compiler/Fable/compare/e33c57870454fea189a3eb33519f583a5003f8c3..2098f64a25e96385306ef19ed8c289f3b6c84db9)</small></strong>
|
|
36
|
+
|
|
37
|
+
## 2.9.0 - 2026-10-16
|
|
38
|
+
|
|
39
|
+
### 🚀 Features
|
|
40
|
+
|
|
41
|
+
* *(js/ts/python/beam)* Support Async.TryCancelled (#5083) ([1643297d](https://github.com/fable-compiler/Fable/commit/1643297d9297fef536c8d10091d5b0d1fad77af7))
|
|
42
|
+
|
|
43
|
+
### 🐞 Bug Fixes
|
|
44
|
+
|
|
45
|
+
* *(js/ts)* Avoid full array copy in Encoding.GetString (#5069) ([e6b72ec7](https://github.com/fable-compiler/Fable/commit/e6b72ec73be454bd3b3233167542a65fc6553c8a))
|
|
46
|
+
* *(js/ts/python)* Preserve cancelled cleanup and generic unit callbacks (#5062) ([5dd6b497](https://github.com/fable-compiler/Fable/commit/5dd6b4979e79c8f7c4632cbfb5254d6cf0d2e8d2))
|
|
47
|
+
|
|
48
|
+
<strong><small>[View changes on Github](https://github.com/fable-compiler/Fable/compare/148f989e1b37b3f6560c3dda615b6a3a8efffcb8..e33c57870454fea189a3eb33519f583a5003f8c3)</small></strong>
|
|
49
|
+
|
|
18
50
|
## 2.8.1 - 2026-10-12
|
|
19
51
|
|
|
20
52
|
### 🐞 Bug Fixes
|
package/Decimal.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import Decimal from "./lib/big.js";
|
|
2
2
|
import { symbol } from "./Numeric.js";
|
|
3
|
-
import { FSharpRef } from "./Types.js";
|
|
4
3
|
import { Exception, combineHashCodes } from "./Util.js";
|
|
5
4
|
import { fromDecimal } from "./BigInt.js";
|
|
6
5
|
import * as bigInt from "./BigInt.js";
|
|
7
6
|
Decimal.prototype.GetHashCode = function () {
|
|
8
|
-
|
|
7
|
+
const digits = this.c;
|
|
8
|
+
if (digits[0] === 0) {
|
|
9
|
+
return combineHashCodes([1, 0, 0]);
|
|
10
|
+
}
|
|
11
|
+
let end = digits.length;
|
|
12
|
+
while (digits[end - 1] === 0) {
|
|
13
|
+
end--;
|
|
14
|
+
}
|
|
15
|
+
return combineHashCodes([this.s, this.e].concat(digits.slice(0, end)));
|
|
9
16
|
};
|
|
10
17
|
Decimal.prototype.Equals = function (x) {
|
|
11
18
|
return !this.cmp(x);
|
|
@@ -37,7 +44,7 @@ export function equals(x, y) {
|
|
|
37
44
|
}
|
|
38
45
|
export function abs(x) { return x.abs(); }
|
|
39
46
|
export function sign(x) { return x.lt(get_Zero) ? -1 : x.gt(get_Zero) ? 1 : 0; }
|
|
40
|
-
export function max(x, y) { return x.
|
|
47
|
+
export function max(x, y) { return x.lt(y) ? y : x; }
|
|
41
48
|
export function min(x, y) { return x.lt(y) ? x : y; }
|
|
42
49
|
export function maxMagnitude(x, y) { return abs(x).gt(abs(y)) ? x : y; }
|
|
43
50
|
export function minMagnitude(x, y) { return abs(x).lt(abs(y)) ? x : y; }
|
|
@@ -94,23 +101,79 @@ export const negate = op_UnaryNegation;
|
|
|
94
101
|
export function toString(x) {
|
|
95
102
|
return x.toString();
|
|
96
103
|
}
|
|
97
|
-
|
|
104
|
+
const NumberStyles = {
|
|
105
|
+
AllowLeadingWhite: 1,
|
|
106
|
+
AllowTrailingWhite: 2,
|
|
107
|
+
AllowLeadingSign: 4,
|
|
108
|
+
AllowTrailingSign: 8,
|
|
109
|
+
AllowParentheses: 16,
|
|
110
|
+
AllowDecimalPoint: 32,
|
|
111
|
+
AllowThousands: 64,
|
|
112
|
+
AllowExponent: 128,
|
|
113
|
+
AllowHexSpecifier: 512,
|
|
114
|
+
Number: 111,
|
|
115
|
+
};
|
|
116
|
+
// The digits of a decimal string once whitespace, sign and parentheses are stripped
|
|
117
|
+
function digitsPattern(style) {
|
|
118
|
+
const integral = style & NumberStyles.AllowThousands ? "\\d+(?:,\\d+)*" : "\\d+";
|
|
119
|
+
const point = style & NumberStyles.AllowDecimalPoint ? "(?:\\.\\d*)?" : "";
|
|
120
|
+
const leadingPoint = style & NumberStyles.AllowDecimalPoint ? "|\\.\\d+" : "";
|
|
121
|
+
const exponent = style & NumberStyles.AllowExponent ? "(?:[eE][+-]?\\d+)?" : "";
|
|
122
|
+
return new RegExp(`^(?:${integral}${point}${leadingPoint})${exponent}$`);
|
|
123
|
+
}
|
|
124
|
+
// Returns undefined when the string does not have the format allowed by the style
|
|
125
|
+
function parseWithStyle(str, style) {
|
|
126
|
+
if (style & NumberStyles.AllowHexSpecifier) {
|
|
127
|
+
throw new Exception("The number style AllowHexSpecifier is not supported on floating point data types.");
|
|
128
|
+
}
|
|
129
|
+
let s = str;
|
|
130
|
+
if (style & NumberStyles.AllowLeadingWhite) {
|
|
131
|
+
s = s.replace(/^\s+/, "");
|
|
132
|
+
}
|
|
133
|
+
if (style & NumberStyles.AllowTrailingWhite) {
|
|
134
|
+
s = s.replace(/\s+$/, "");
|
|
135
|
+
}
|
|
136
|
+
let negative = false;
|
|
137
|
+
if (style & NumberStyles.AllowParentheses && s.startsWith("(") && s.endsWith(")")) {
|
|
138
|
+
s = s.slice(1, -1);
|
|
139
|
+
negative = true;
|
|
140
|
+
}
|
|
141
|
+
if (style & NumberStyles.AllowLeadingSign && /^[+-]/.test(s)) {
|
|
142
|
+
negative = s[0] === "-" ? !negative : negative;
|
|
143
|
+
s = s.slice(1);
|
|
144
|
+
}
|
|
145
|
+
else if (style & NumberStyles.AllowTrailingSign && /[+-]$/.test(s)) {
|
|
146
|
+
negative = s[s.length - 1] === "-" ? !negative : negative;
|
|
147
|
+
s = s.slice(0, -1);
|
|
148
|
+
}
|
|
149
|
+
if (!digitsPattern(style).test(s)) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
const d = new Decimal(s.replace(/,/g, ""));
|
|
153
|
+
if (negative) {
|
|
154
|
+
d.s = -1;
|
|
155
|
+
}
|
|
156
|
+
return d;
|
|
157
|
+
}
|
|
158
|
+
export function tryParse(str, style, defValue) {
|
|
98
159
|
try {
|
|
99
|
-
|
|
160
|
+
const d = parseWithStyle(str, style);
|
|
161
|
+
if (d === undefined) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
defValue.contents = d;
|
|
100
165
|
return true;
|
|
101
166
|
}
|
|
102
167
|
catch {
|
|
103
168
|
return false;
|
|
104
169
|
}
|
|
105
170
|
}
|
|
106
|
-
export function parse(str) {
|
|
107
|
-
const
|
|
108
|
-
if (
|
|
109
|
-
return defValue.contents;
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
171
|
+
export function parse(str, style = NumberStyles.Number) {
|
|
172
|
+
const d = parseWithStyle(str, style);
|
|
173
|
+
if (d === undefined) {
|
|
112
174
|
throw new Exception(`The input string ${str} was not in a correct format.`);
|
|
113
175
|
}
|
|
176
|
+
return d;
|
|
114
177
|
}
|
|
115
178
|
export function toNumber(x) {
|
|
116
179
|
return +x;
|
|
@@ -182,6 +245,32 @@ function getInt32Bits(hexDigits, offset) {
|
|
|
182
245
|
}
|
|
183
246
|
return bits;
|
|
184
247
|
}
|
|
248
|
+
const OVERFLOW = "Value was either too large or too small for a Decimal.";
|
|
249
|
+
// The first double outside the decimal range
|
|
250
|
+
const MAX_DOUBLE = 2 ** 96;
|
|
251
|
+
function fromFloat(n, significantDigits) {
|
|
252
|
+
if (!isFinite(n) || Math.abs(n) >= MAX_DOUBLE) {
|
|
253
|
+
throw new Exception(OVERFLOW);
|
|
254
|
+
}
|
|
255
|
+
const exact = Math.abs(n) >= 1e21 ? BigInt(n).toString() : n.toFixed(100);
|
|
256
|
+
const d = new Decimal(exact).prec(significantDigits, 2);
|
|
257
|
+
const digits = d.c;
|
|
258
|
+
let end = digits.length;
|
|
259
|
+
while (end > 1 && digits[end - 1] === 0) {
|
|
260
|
+
end--;
|
|
261
|
+
}
|
|
262
|
+
d.c = digits.slice(0, end);
|
|
263
|
+
if (d.c[0] === 0) {
|
|
264
|
+
d.e = 0;
|
|
265
|
+
}
|
|
266
|
+
return d;
|
|
267
|
+
}
|
|
268
|
+
export function fromFloat64(n) {
|
|
269
|
+
return fromFloat(n, 15);
|
|
270
|
+
}
|
|
271
|
+
export function fromFloat32(n) {
|
|
272
|
+
return fromFloat(n, 7);
|
|
273
|
+
}
|
|
185
274
|
export function fromIntArray(bits) {
|
|
186
275
|
return fromInts(bits[0], bits[1], bits[2], bits[3]);
|
|
187
276
|
}
|
package/Encoding.js
CHANGED
|
@@ -90,6 +90,27 @@ function utf8_decode(bytes) {
|
|
|
90
90
|
}
|
|
91
91
|
return chars.join("");
|
|
92
92
|
}
|
|
93
|
+
function toUint8Array(bytes, index, count) {
|
|
94
|
+
if (ArrayBuffer.isView(bytes)) {
|
|
95
|
+
const buffer = new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
96
|
+
if (index != null && count != null) {
|
|
97
|
+
return buffer.subarray(index, index + count);
|
|
98
|
+
}
|
|
99
|
+
else if (index != null) {
|
|
100
|
+
return buffer.subarray(index);
|
|
101
|
+
}
|
|
102
|
+
return buffer;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
if (index != null && count != null) {
|
|
106
|
+
return Uint8Array.from(Array.prototype.slice.call(bytes, index, index + count));
|
|
107
|
+
}
|
|
108
|
+
else if (index != null) {
|
|
109
|
+
return Uint8Array.from(Array.prototype.slice.call(bytes, index));
|
|
110
|
+
}
|
|
111
|
+
return Uint8Array.from(bytes);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
93
114
|
class UTF16LE {
|
|
94
115
|
getBytes(str, index, count) {
|
|
95
116
|
str = Array.isArray(str) ? str.join("") : str;
|
|
@@ -111,14 +132,7 @@ class UTF16LE {
|
|
|
111
132
|
}
|
|
112
133
|
}
|
|
113
134
|
getString(bytes, index, count) {
|
|
114
|
-
const
|
|
115
|
-
let buffer = new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
|
|
116
|
-
if (index != null && count != null) {
|
|
117
|
-
buffer = buffer.subarray(index, index + count);
|
|
118
|
-
}
|
|
119
|
-
else if (index != null) {
|
|
120
|
-
buffer = buffer.subarray(index);
|
|
121
|
-
}
|
|
135
|
+
const buffer = toUint8Array(bytes, index, count);
|
|
122
136
|
// Allow to compile for Browser environment without @types/node being installed
|
|
123
137
|
// See https://github.com/fable-compiler/Fable/issues/4368
|
|
124
138
|
const g = globalThis;
|
|
@@ -157,14 +171,7 @@ class UTF8 {
|
|
|
157
171
|
}
|
|
158
172
|
}
|
|
159
173
|
getString(bytes, index, count) {
|
|
160
|
-
const
|
|
161
|
-
let buffer = new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
|
|
162
|
-
if (index != null && count != null) {
|
|
163
|
-
buffer = buffer.subarray(index, index + count);
|
|
164
|
-
}
|
|
165
|
-
else if (index != null) {
|
|
166
|
-
buffer = buffer.subarray(index);
|
|
167
|
-
}
|
|
174
|
+
const buffer = toUint8Array(bytes, index, count);
|
|
168
175
|
// Allow to compile for Browser environment without @types/node being installed
|
|
169
176
|
// See https://github.com/fable-compiler/Fable/issues/4368
|
|
170
177
|
const g = globalThis;
|
package/MailboxProcessor.js
CHANGED
|
@@ -96,6 +96,10 @@ export function postAndAsyncReply($this, buildMessage) {
|
|
|
96
96
|
}
|
|
97
97
|
const reply = {
|
|
98
98
|
reply: (res) => {
|
|
99
|
+
// .NET AsyncReplyChannel.Reply ignores a second reply
|
|
100
|
+
if (replied) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
99
103
|
result = res;
|
|
100
104
|
replied = true;
|
|
101
105
|
checkCompletion();
|
package/Stopwatch.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Timestamps are in microseconds, the resolution performance.now() can offer
|
|
2
|
+
const ticksPerMillisecond = 1000;
|
|
3
|
+
export class Stopwatch {
|
|
4
|
+
constructor() {
|
|
5
|
+
// Milliseconds measured before the last Start
|
|
6
|
+
this.elapsed = 0;
|
|
7
|
+
// performance.now() at the last Start, while running
|
|
8
|
+
this.startedAt = undefined;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function create() {
|
|
12
|
+
return new Stopwatch();
|
|
13
|
+
}
|
|
14
|
+
export function startNew() {
|
|
15
|
+
const sw = new Stopwatch();
|
|
16
|
+
start(sw);
|
|
17
|
+
return sw;
|
|
18
|
+
}
|
|
19
|
+
export function start(sw) {
|
|
20
|
+
if (sw.startedAt === undefined) {
|
|
21
|
+
sw.startedAt = performance.now();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function stop(sw) {
|
|
25
|
+
if (sw.startedAt !== undefined) {
|
|
26
|
+
sw.elapsed += performance.now() - sw.startedAt;
|
|
27
|
+
sw.startedAt = undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function reset(sw) {
|
|
31
|
+
sw.elapsed = 0;
|
|
32
|
+
sw.startedAt = undefined;
|
|
33
|
+
}
|
|
34
|
+
export function restart(sw) {
|
|
35
|
+
sw.elapsed = 0;
|
|
36
|
+
sw.startedAt = performance.now();
|
|
37
|
+
}
|
|
38
|
+
export function isRunning(sw) {
|
|
39
|
+
return sw.startedAt !== undefined;
|
|
40
|
+
}
|
|
41
|
+
function rawElapsedMilliseconds(sw) {
|
|
42
|
+
return sw.elapsed + (sw.startedAt === undefined ? 0 : performance.now() - sw.startedAt);
|
|
43
|
+
}
|
|
44
|
+
// In units of Frequency, like .NET (not TimeSpan ticks)
|
|
45
|
+
export function elapsedTicks(sw) {
|
|
46
|
+
return BigInt(Math.trunc(rawElapsedMilliseconds(sw) * ticksPerMillisecond));
|
|
47
|
+
}
|
|
48
|
+
export function elapsedMilliseconds(sw) {
|
|
49
|
+
return elapsedTicks(sw) / BigInt(ticksPerMillisecond);
|
|
50
|
+
}
|
|
51
|
+
export function elapsedTotalMilliseconds(sw) {
|
|
52
|
+
return Number(elapsedTicks(sw)) / ticksPerMillisecond;
|
|
53
|
+
}
|
|
54
|
+
export function frequency() {
|
|
55
|
+
return BigInt(ticksPerMillisecond * 1000);
|
|
56
|
+
}
|
|
57
|
+
export function isHighResolution() {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
export function getTimestamp() {
|
|
61
|
+
return BigInt(Math.trunc(performance.now() * ticksPerMillisecond));
|
|
62
|
+
}
|
|
63
|
+
export function getElapsedTotalMilliseconds(startingTimestamp, endingTimestamp) {
|
|
64
|
+
return Number((endingTimestamp ?? getTimestamp()) - startingTimestamp) / ticksPerMillisecond;
|
|
65
|
+
}
|
package/String.js
CHANGED
|
@@ -426,6 +426,10 @@ export function format(str, ...args) {
|
|
|
426
426
|
break;
|
|
427
427
|
case "g":
|
|
428
428
|
case "G": {
|
|
429
|
+
if (precision == null && typeof rep !== "number" && typeof rep !== "bigint") {
|
|
430
|
+
rep = String(rep);
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
429
433
|
rep = precision != null ? toPrecision(rep, precision) : toPrecision(rep);
|
|
430
434
|
// Handle exponential notation: only trim trailing zeros from mantissa, not from exponent.
|
|
431
435
|
// .NET G format guarantees an exponent of at least 2 digits with an explicit sign (e.g. "E-07").
|
package/Task.js
CHANGED
|
@@ -17,6 +17,28 @@ export function fromResult(value) {
|
|
|
17
17
|
export function zero() {
|
|
18
18
|
return Promise.resolve();
|
|
19
19
|
}
|
|
20
|
+
// Like .NET, -1 waits until the token is cancelled
|
|
21
|
+
export function delay(millisecondsDelay, cancellationToken) {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
if (cancellationToken?.isCancelled) {
|
|
24
|
+
reject(new OperationCanceledException());
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let tokenId;
|
|
28
|
+
const timeoutId = millisecondsDelay === -1 ? undefined : setTimeout(() => {
|
|
29
|
+
if (tokenId !== undefined) {
|
|
30
|
+
cancellationToken.removeListener(tokenId);
|
|
31
|
+
}
|
|
32
|
+
resolve();
|
|
33
|
+
}, millisecondsDelay);
|
|
34
|
+
if (cancellationToken != null) {
|
|
35
|
+
tokenId = cancellationToken.addListener(() => {
|
|
36
|
+
clearTimeout(timeoutId);
|
|
37
|
+
reject(new OperationCanceledException());
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
20
42
|
// Task<T> = Promise<T> in JS/TS. GetAwaiter/GetResult return the Promise itself;
|
|
21
43
|
// callers should use Async.AwaitTask to extract the value in an async context.
|
|
22
44
|
export function getAwaiter(t) {
|
package/big.d.ts
CHANGED
|
@@ -202,6 +202,7 @@ export interface Big extends CustomNumeric {
|
|
|
202
202
|
* @throws `!Big.RM!` if rm is invalid.
|
|
203
203
|
*/
|
|
204
204
|
round(dp?: number, rm?: RoundingMode): Big;
|
|
205
|
+
prec(sd: number, rm?: RoundingMode): Big;
|
|
205
206
|
/**
|
|
206
207
|
* Returns a Big number whose value is the square root of this Big number.
|
|
207
208
|
*
|
package/lib/big.js
CHANGED
|
@@ -67,7 +67,6 @@ function _Big_() {
|
|
|
67
67
|
x.s = n.s;
|
|
68
68
|
x.e = n.e;
|
|
69
69
|
x.c = n.c.slice();
|
|
70
|
-
normalize(x);
|
|
71
70
|
}
|
|
72
71
|
else {
|
|
73
72
|
if (typeof n !== 'string') {
|
|
@@ -91,14 +90,6 @@ function _Big_() {
|
|
|
91
90
|
Big.strict = STRICT;
|
|
92
91
|
return Big;
|
|
93
92
|
}
|
|
94
|
-
function normalize(x) {
|
|
95
|
-
// x = round(x, DP, 0);
|
|
96
|
-
if (x.c.length > 1 && !x.c[0]) {
|
|
97
|
-
let i = x.c.findIndex(x => x);
|
|
98
|
-
x.c = x.c.slice(i);
|
|
99
|
-
x.e = x.e - i;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
93
|
/*
|
|
103
94
|
* Parse the number or string value passed to a Big constructor.
|
|
104
95
|
*
|
|
@@ -128,15 +119,13 @@ function parse(x, n) {
|
|
|
128
119
|
e = n.length;
|
|
129
120
|
}
|
|
130
121
|
nl = n.length;
|
|
131
|
-
// Determine leading zeros
|
|
132
|
-
for (i = 0; i <
|
|
122
|
+
// Determine leading zeros.
|
|
123
|
+
for (i = 0; i < nl && n.charAt(i) == '0';)
|
|
133
124
|
++i;
|
|
134
|
-
// original version (ignores decimal point).
|
|
135
|
-
// // Determine leading zeros.
|
|
136
|
-
// for (i = 0; i < nl && n.charAt(i) == '0';) ++i;
|
|
137
125
|
if (i == nl) {
|
|
138
|
-
// Zero.
|
|
139
|
-
x.c = [
|
|
126
|
+
// Zero, keeping the scale: 0.00 is c = [0], e = -2.
|
|
127
|
+
x.c = [0];
|
|
128
|
+
x.e = nl > e ? e - nl : 0;
|
|
140
129
|
}
|
|
141
130
|
else {
|
|
142
131
|
x.e = e - i - 1;
|
|
@@ -150,8 +139,7 @@ function parse(x, n) {
|
|
|
150
139
|
// // Convert string to array of digits without leading/trailing zeros.
|
|
151
140
|
// for (e = 0; i <= nl;) x.c[e++] = +n.charAt(i++);
|
|
152
141
|
}
|
|
153
|
-
|
|
154
|
-
return x;
|
|
142
|
+
return fit(x);
|
|
155
143
|
}
|
|
156
144
|
/*
|
|
157
145
|
* Round Big x to a maximum of sd significant digits using rounding mode rm.
|
|
@@ -171,17 +159,11 @@ function round(x, sd, rm, more) {
|
|
|
171
159
|
if (sd < 1) {
|
|
172
160
|
more =
|
|
173
161
|
rm === 3 && (more || !!xc[0]) || sd === 0 && (rm === 1 && xc[0] >= 5 ||
|
|
174
|
-
rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc
|
|
162
|
+
rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc.some((d, i) => i > 0 && d))));
|
|
175
163
|
xc.length = 1;
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
xc[0] = 1;
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
// Zero.
|
|
183
|
-
xc[0] = x.e = 0;
|
|
184
|
-
}
|
|
164
|
+
// 1, 0.1, 0.01, 0.001, 0.0001 etc., or zero at the same place.
|
|
165
|
+
x.e = x.e - sd + 1;
|
|
166
|
+
xc[0] = more ? 1 : 0;
|
|
185
167
|
}
|
|
186
168
|
else if (sd < xc.length) {
|
|
187
169
|
// xc[sd] is the digit after the digit that may be rounded up.
|
|
@@ -189,7 +171,7 @@ function round(x, sd, rm, more) {
|
|
|
189
171
|
more =
|
|
190
172
|
rm === 1 && xc[sd] >= 5 ||
|
|
191
173
|
rm === 2 && (xc[sd] > 5 || xc[sd] === 5 &&
|
|
192
|
-
(more || xc
|
|
174
|
+
(more || xc.some((d, i) => i > sd && d) || xc[sd - 1] & 1)) ||
|
|
193
175
|
rm === 3 && (more || !isZero);
|
|
194
176
|
// Remove any digits after the required precision.
|
|
195
177
|
xc.length = sd--;
|
|
@@ -204,14 +186,59 @@ function round(x, sd, rm, more) {
|
|
|
204
186
|
}
|
|
205
187
|
}
|
|
206
188
|
}
|
|
207
|
-
// Remove trailing zeros.
|
|
208
|
-
for (sd = xc.length; !xc[--sd];)
|
|
209
|
-
xc.pop();
|
|
210
189
|
}
|
|
211
190
|
return x;
|
|
212
191
|
}
|
|
213
|
-
|
|
214
|
-
|
|
192
|
+
// Largest System.Decimal mantissa, 2^96 - 1.
|
|
193
|
+
var MAX_MANTISSA = '79228162514264337593543950335'.split('').map(Number), OVERFLOW = 'Value was either too large or too small for a Decimal.';
|
|
194
|
+
/*
|
|
195
|
+
* Return the number of decimal places of Big x.
|
|
196
|
+
*/
|
|
197
|
+
function scaleOf(x) {
|
|
198
|
+
return x.c.length - x.e - 1;
|
|
199
|
+
}
|
|
200
|
+
/*
|
|
201
|
+
* Pad Big x with trailing zeros up to dp decimal places.
|
|
202
|
+
*/
|
|
203
|
+
function padScale(x, dp) {
|
|
204
|
+
if (!x.c[0]) {
|
|
205
|
+
x.e = Math.min(x.e, -dp);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
for (; scaleOf(x) < dp;)
|
|
209
|
+
x.c.push(0);
|
|
210
|
+
}
|
|
211
|
+
return x;
|
|
212
|
+
}
|
|
213
|
+
/*
|
|
214
|
+
* Return true if the digits c, padded with zeros to the length of MAX_MANTISSA, exceed it.
|
|
215
|
+
*/
|
|
216
|
+
function exceedsMax(c) {
|
|
217
|
+
for (var i = 0; i < MAX_MANTISSA.length; i++) {
|
|
218
|
+
var d = i < c.length ? c[i] : 0;
|
|
219
|
+
if (d !== MAX_MANTISSA[i])
|
|
220
|
+
return d > MAX_MANTISSA[i];
|
|
221
|
+
}
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
/*
|
|
225
|
+
* Round Big x half to even so that it fits a System.Decimal: at most Big.DP decimal places
|
|
226
|
+
* and a mantissa no larger than MAX_MANTISSA. Throws when no decimal place is left to drop.
|
|
227
|
+
*/
|
|
228
|
+
function fit(x) {
|
|
229
|
+
var scale = scaleOf(x), dp = Math.min(scale, Big.DP, Big.DP - x.e);
|
|
230
|
+
if (x.e > Big.DP)
|
|
231
|
+
throw Error(OVERFLOW);
|
|
232
|
+
if (dp < scale)
|
|
233
|
+
round(x, x.e + 1 + dp, 2);
|
|
234
|
+
if (x.e > Big.DP)
|
|
235
|
+
throw Error(OVERFLOW);
|
|
236
|
+
// Both the value and the mantissa itself must not exceed MAX_MANTISSA.
|
|
237
|
+
if (x.e === Big.DP && exceedsMax(x.c))
|
|
238
|
+
throw Error(OVERFLOW);
|
|
239
|
+
if (x.c.length === MAX_MANTISSA.length && exceedsMax(x.c))
|
|
240
|
+
round(x, x.c.length - 1, 2);
|
|
241
|
+
return x;
|
|
215
242
|
}
|
|
216
243
|
/*
|
|
217
244
|
* Return a string representing the value of Big x in normal or exponential notation.
|
|
@@ -221,6 +248,8 @@ function stringify(x, doExponential, isNonzero) {
|
|
|
221
248
|
var e = x.e, s = x.c.join(''), n = s.length;
|
|
222
249
|
// Exponential notation?
|
|
223
250
|
if (doExponential) {
|
|
251
|
+
if (!x.c[0])
|
|
252
|
+
e = 0;
|
|
224
253
|
s = s.charAt(0) + (n > 1 ? '.' + s.slice(1) : '') + (e < 0 ? 'e' : 'e+') + e;
|
|
225
254
|
// Normal notation.
|
|
226
255
|
}
|
|
@@ -292,20 +321,31 @@ P.cmp = function (y) {
|
|
|
292
321
|
* if necessary, to a maximum of Big.DP decimal places using rounding mode Big.RM.
|
|
293
322
|
*/
|
|
294
323
|
P.div = function (y) {
|
|
295
|
-
var Big = this.constructor,
|
|
296
|
-
b = y.c, // divisor
|
|
297
|
-
k = x.s == y.s ? 1 : -1, dp = Big.DP;
|
|
324
|
+
var Big = this.constructor, dp = Big.DP;
|
|
298
325
|
if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
|
|
299
326
|
throw Error(INVALID_DP);
|
|
300
327
|
}
|
|
328
|
+
return divide(new Big(this), new Big(y), dp, 2);
|
|
329
|
+
};
|
|
330
|
+
/*
|
|
331
|
+
* Return Big x divided by Big y to dp decimal places using rounding mode rm.
|
|
332
|
+
* Both are modified.
|
|
333
|
+
*/
|
|
334
|
+
function divide(x, y, dp, rm) {
|
|
335
|
+
var a = x.c, // dividend
|
|
336
|
+
b = y.c, // divisor
|
|
337
|
+
k = x.s == y.s ? 1 : -1;
|
|
301
338
|
// Divisor is zero?
|
|
302
339
|
if (!b[0]) {
|
|
303
340
|
throw Error(DIV_BY_ZERO);
|
|
304
341
|
}
|
|
342
|
+
// Scale of the exact quotient is at least the scale of x less the scale of y.
|
|
343
|
+
var minScale = Math.max(0, scaleOf(x) - scaleOf(y));
|
|
305
344
|
// Dividend is 0? Return +-0.
|
|
306
345
|
if (!a[0]) {
|
|
307
346
|
y.s = k;
|
|
308
|
-
y.c = [
|
|
347
|
+
y.c = [0];
|
|
348
|
+
y.e = -minScale;
|
|
309
349
|
return y;
|
|
310
350
|
}
|
|
311
351
|
var bl, bt, n, cmp, ri, bz = b.slice(), ai = bl = b.length, al = a.length, r = a.slice(0, bl), // remainder
|
|
@@ -369,11 +409,20 @@ P.div = function (y) {
|
|
|
369
409
|
q.e--;
|
|
370
410
|
p--;
|
|
371
411
|
}
|
|
412
|
+
var exact = r[0] === UNDEFINED;
|
|
372
413
|
// Round?
|
|
373
414
|
if (qi > p)
|
|
374
|
-
round(q, p,
|
|
415
|
+
round(q, p, rm, !exact);
|
|
416
|
+
fit(q);
|
|
417
|
+
if (!q.c[0]) {
|
|
418
|
+
q.e = 0;
|
|
419
|
+
}
|
|
420
|
+
else if (exact) {
|
|
421
|
+
for (; scaleOf(q) > minScale && !q.c[q.c.length - 1];)
|
|
422
|
+
q.c.pop();
|
|
423
|
+
}
|
|
375
424
|
return q;
|
|
376
|
-
}
|
|
425
|
+
}
|
|
377
426
|
/*
|
|
378
427
|
* Return true if the value of this Big is equal to the value of Big y, otherwise return false.
|
|
379
428
|
*/
|
|
@@ -420,6 +469,7 @@ P.minus = P.sub = function (y) {
|
|
|
420
469
|
var xc = x.c.slice(), xe = x.e, yc = y.c, ye = y.e;
|
|
421
470
|
// Either zero?
|
|
422
471
|
if (!xc[0] || !yc[0]) {
|
|
472
|
+
var dp = Math.max(scaleOf(x), scaleOf(y));
|
|
423
473
|
if (yc[0]) {
|
|
424
474
|
y.s = -b;
|
|
425
475
|
}
|
|
@@ -429,7 +479,7 @@ P.minus = P.sub = function (y) {
|
|
|
429
479
|
else {
|
|
430
480
|
y.s = 1;
|
|
431
481
|
}
|
|
432
|
-
return y;
|
|
482
|
+
return padScale(y, dp);
|
|
433
483
|
}
|
|
434
484
|
// Determine which is the bigger number. Prepend zeros to equalise exponents.
|
|
435
485
|
if (a = xe - ye) {
|
|
@@ -480,9 +530,8 @@ P.minus = P.sub = function (y) {
|
|
|
480
530
|
}
|
|
481
531
|
xc[j] -= yc[j];
|
|
482
532
|
}
|
|
483
|
-
//
|
|
484
|
-
|
|
485
|
-
xc.pop();
|
|
533
|
+
// The result keeps the larger scale.
|
|
534
|
+
var dp = xc.length - ye - 1;
|
|
486
535
|
// Remove leading zeros and adjust exponent accordingly.
|
|
487
536
|
for (; xc[0] === 0;) {
|
|
488
537
|
xc.shift();
|
|
@@ -492,11 +541,12 @@ P.minus = P.sub = function (y) {
|
|
|
492
541
|
// n - n = +0
|
|
493
542
|
y.s = 1;
|
|
494
543
|
// Result must be zero.
|
|
495
|
-
xc = [
|
|
544
|
+
xc = [0];
|
|
545
|
+
ye = -dp;
|
|
496
546
|
}
|
|
497
547
|
y.c = xc;
|
|
498
548
|
y.e = ye;
|
|
499
|
-
return y;
|
|
549
|
+
return fit(y);
|
|
500
550
|
};
|
|
501
551
|
/*
|
|
502
552
|
* Return a new Big whose value is the value of this Big modulo the value of Big y.
|
|
@@ -512,12 +562,7 @@ P.mod = function (y) {
|
|
|
512
562
|
y.s = b;
|
|
513
563
|
if (ygtx)
|
|
514
564
|
return new Big(x);
|
|
515
|
-
|
|
516
|
-
b = Big.RM;
|
|
517
|
-
Big.DP = Big.RM = 0;
|
|
518
|
-
x = x.div(y);
|
|
519
|
-
Big.DP = a;
|
|
520
|
-
Big.RM = b;
|
|
565
|
+
x = divide(x, new Big(y), 0, 0);
|
|
521
566
|
return this.minus(x.times(y));
|
|
522
567
|
};
|
|
523
568
|
/*
|
|
@@ -533,6 +578,7 @@ P.plus = P.add = function (y) {
|
|
|
533
578
|
var xe = x.e, xc = x.c, ye = y.e, yc = y.c;
|
|
534
579
|
// Either zero?
|
|
535
580
|
if (!xc[0] || !yc[0]) {
|
|
581
|
+
var dp = Math.max(scaleOf(x), scaleOf(y));
|
|
536
582
|
if (!yc[0]) {
|
|
537
583
|
if (xc[0]) {
|
|
538
584
|
y = new Big(x);
|
|
@@ -541,7 +587,7 @@ P.plus = P.add = function (y) {
|
|
|
541
587
|
y.s = x.s;
|
|
542
588
|
}
|
|
543
589
|
}
|
|
544
|
-
return y;
|
|
590
|
+
return padScale(y, dp);
|
|
545
591
|
}
|
|
546
592
|
xc = xc.slice();
|
|
547
593
|
// Prepend zeros to equalise exponents.
|
|
@@ -575,12 +621,9 @@ P.plus = P.add = function (y) {
|
|
|
575
621
|
xc.unshift(k);
|
|
576
622
|
++ye;
|
|
577
623
|
}
|
|
578
|
-
// Remove trailing zeros.
|
|
579
|
-
for (e = xc.length; xc[--e] === 0;)
|
|
580
|
-
xc.pop();
|
|
581
624
|
y.c = xc;
|
|
582
625
|
y.e = ye;
|
|
583
|
-
return y;
|
|
626
|
+
return fit(y);
|
|
584
627
|
};
|
|
585
628
|
/*
|
|
586
629
|
* Return a Big whose value is the value of this Big raised to the power n.
|
|
@@ -681,7 +724,9 @@ P.times = P.mul = function (y) {
|
|
|
681
724
|
y.s = x.s == y.s ? 1 : -1;
|
|
682
725
|
// Return signed 0 if either 0.
|
|
683
726
|
if (!xc[0] || !yc[0]) {
|
|
684
|
-
|
|
727
|
+
var dp = scaleOf(x) + scaleOf(y);
|
|
728
|
+
y.c = [0];
|
|
729
|
+
y.e = -dp;
|
|
685
730
|
return y;
|
|
686
731
|
}
|
|
687
732
|
// Initialise exponent of result as x.e + y.e.
|
|
@@ -717,11 +762,8 @@ P.times = P.mul = function (y) {
|
|
|
717
762
|
++y.e;
|
|
718
763
|
else
|
|
719
764
|
c.shift();
|
|
720
|
-
// Remove trailing zeros.
|
|
721
|
-
for (i = c.length; !c[--i];)
|
|
722
|
-
c.pop();
|
|
723
765
|
y.c = c;
|
|
724
|
-
return y;
|
|
766
|
+
return fit(y);
|
|
725
767
|
};
|
|
726
768
|
/*
|
|
727
769
|
* Return a string representing the value of this Big in exponential notation rounded to dp fixed
|
|
@@ -731,7 +773,7 @@ P.times = P.mul = function (y) {
|
|
|
731
773
|
* rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).
|
|
732
774
|
*/
|
|
733
775
|
P.toExponential = function (dp, rm) {
|
|
734
|
-
var x = this, n =
|
|
776
|
+
var x = this, n = x.c[0];
|
|
735
777
|
if (dp !== UNDEFINED) {
|
|
736
778
|
if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
|
|
737
779
|
throw Error(INVALID_DP);
|
|
@@ -740,7 +782,7 @@ P.toExponential = function (dp, rm) {
|
|
|
740
782
|
for (; x.c.length < dp;)
|
|
741
783
|
x.c.push(0);
|
|
742
784
|
}
|
|
743
|
-
return stringify(x, true, n);
|
|
785
|
+
return stringify(x, true, !!n);
|
|
744
786
|
};
|
|
745
787
|
/*
|
|
746
788
|
* Return a string representing the value of this Big in normal notation rounded to dp fixed
|
|
@@ -758,13 +800,12 @@ P.toFixed = function (dp, rm) {
|
|
|
758
800
|
if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
|
|
759
801
|
throw Error(INVALID_DP);
|
|
760
802
|
}
|
|
761
|
-
x = new x.constructor(x);
|
|
762
|
-
x = round(x, dp + x.e + 1, rm);
|
|
803
|
+
x = round(new x.constructor(x), dp + x.e + 1, rm);
|
|
763
804
|
// x.e may have changed if the value is rounded up.
|
|
764
805
|
for (dp = dp + x.e + 1; x.c.length < dp;)
|
|
765
806
|
x.c.push(0);
|
|
766
807
|
}
|
|
767
|
-
return stringify(x, false,
|
|
808
|
+
return stringify(x, false, !!x.c[0]);
|
|
768
809
|
};
|
|
769
810
|
/*
|
|
770
811
|
* Return a string representing the value of this Big.
|
|
@@ -774,7 +815,7 @@ P.toFixed = function (dp, rm) {
|
|
|
774
815
|
*/
|
|
775
816
|
P.toJSON = P.toString = function () {
|
|
776
817
|
var x = this, Big = x.constructor;
|
|
777
|
-
return stringify(x, x.e <= Big.NE || x.e >= Big.PE,
|
|
818
|
+
return stringify(x, x.e <= Big.NE || x.e >= Big.PE, !!x.c[0]);
|
|
778
819
|
};
|
|
779
820
|
/*
|
|
780
821
|
* Return the value of this Big as a primitve number.
|
|
@@ -796,16 +837,18 @@ P.toNumber = function () {
|
|
|
796
837
|
* rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).
|
|
797
838
|
*/
|
|
798
839
|
P.toPrecision = function (sd, rm) {
|
|
799
|
-
var x = this, Big = x.constructor, n =
|
|
840
|
+
var x = this, Big = x.constructor, n = x.c[0];
|
|
800
841
|
if (sd !== UNDEFINED) {
|
|
801
842
|
if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {
|
|
802
843
|
throw Error(INVALID + 'precision');
|
|
803
844
|
}
|
|
804
845
|
x = round(new Big(x), sd, rm);
|
|
846
|
+
if (!x.c[0])
|
|
847
|
+
x.e = 0;
|
|
805
848
|
for (; x.c.length < sd;)
|
|
806
849
|
x.c.push(0);
|
|
807
850
|
}
|
|
808
|
-
return stringify(x, sd <= x.e || x.e <= Big.NE || x.e >= Big.PE, n);
|
|
851
|
+
return stringify(x, sd <= x.e || x.e <= Big.NE || x.e >= Big.PE, !!n);
|
|
809
852
|
};
|
|
810
853
|
/*
|
|
811
854
|
* Return a string representing the value of this Big.
|
package/package.json
CHANGED