@cjhd/cj-decimal 1.0.0 → 1.0.1
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/assets/Decimal.d.ts +464 -0
- package/dist/cocos/assets/Decimal.js +4 -0
- package/dist/cocos/index.js +4 -0
- package/{index.ts → index.d.ts} +2 -2
- package/package.json +26 -7
- package/assets/Decimal.ts +0 -1428
- package/assets/Decimal.ts.meta +0 -9
- package/assets.meta +0 -9
- package/index.ts.meta +0 -9
- package/package.json.meta +0 -11
- /package/{.cj-decimal.md → README.md} +0 -0
package/assets/Decimal.ts
DELETED
|
@@ -1,1428 +0,0 @@
|
|
|
1
|
-
import { DEV } from 'cc/env';
|
|
2
|
-
|
|
3
|
-
// 精确度默认保留8位小数点
|
|
4
|
-
let DotLen = 8;
|
|
5
|
-
let Scale = Math.pow(10, DotLen);
|
|
6
|
-
let Scale_L = Math.pow(10, DotLen - 1);
|
|
7
|
-
|
|
8
|
-
type DecimalSign = 1 | -1;
|
|
9
|
-
type IntNumber = number;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Decimal 原地修改观察器。
|
|
13
|
-
* 默认不绑定,只有 @EcsObservedDecimal 这类业务装饰器显式绑定后才会触发。
|
|
14
|
-
*/
|
|
15
|
-
export interface IDecimalMutationObserver {
|
|
16
|
-
onDecimalMutated(decimal: Decimal): void;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
type DecimalSnapshot = {
|
|
20
|
-
sign: DecimalSign;
|
|
21
|
-
v1: IntNumber;
|
|
22
|
-
v2: IntNumber;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function decimalStr(str: string) {
|
|
26
|
-
const strLen = str.length;
|
|
27
|
-
if (strLen === DotLen) {
|
|
28
|
-
return str;
|
|
29
|
-
} else if (strLen > DotLen) {
|
|
30
|
-
return str.slice(0, DotLen);
|
|
31
|
-
} else {
|
|
32
|
-
return str + '0'.repeat(DotLen - strLen);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// 获取商数。只处理非负数,结果向下取整。
|
|
37
|
-
// Why: 原实现每次返回 { shang, yu } 对象,add/sub/mul/div/mod 热路径会产生大量临时 GC。
|
|
38
|
-
function intDiv(up: IntNumber, down: IntNumber): IntNumber {
|
|
39
|
-
if (up < down) return 0;
|
|
40
|
-
if (up === down) return 1;
|
|
41
|
-
return Math.floor(up / down);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 获取余数。只处理非负数。
|
|
45
|
-
function intMod(up: IntNumber, down: IntNumber): IntNumber {
|
|
46
|
-
if (up < down) return up;
|
|
47
|
-
if (up === down) return 0;
|
|
48
|
-
return up - intDiv(up, down) * down;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 8 位小数默认 Scale=100000000,v2 * v2 的峰值接近 1e16,已经可能超过 JS 安全整数。
|
|
52
|
-
// 这里把 8 位小数拆成 4+4 位计算 floor((a * b) / Scale),避免使用 BigInt,也避免 unsafe 乘法。
|
|
53
|
-
function mulFractionToScaledFloor(a: IntNumber, b: IntNumber): IntNumber {
|
|
54
|
-
const BASE = 10000;
|
|
55
|
-
const ah = intDiv(a, BASE);
|
|
56
|
-
const al = a - ah * BASE;
|
|
57
|
-
const bh = intDiv(b, BASE);
|
|
58
|
-
const bl = b - bh * BASE;
|
|
59
|
-
const high = ah * bh;
|
|
60
|
-
const mid = ah * bl + al * bh;
|
|
61
|
-
const low = al * bl;
|
|
62
|
-
return high + intDiv(mid * BASE + low, BASE * BASE);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// BigInt 不进入乘法热路径,只用于 div/mod 这类 8 位小数下容易出现中间值溢出的低频精确路径。
|
|
66
|
-
// 使用 globalThis.BigInt 避免 BigInt 字面量,兼容 Cocos 构建链的语法降级。
|
|
67
|
-
const BigIntCtor: ((value: any) => any) | undefined = typeof (globalThis as any).BigInt === 'function'
|
|
68
|
-
? (globalThis as any).BigInt
|
|
69
|
-
: undefined;
|
|
70
|
-
|
|
71
|
-
// 计算阶乘
|
|
72
|
-
// function factorial(n: IntNumber) {
|
|
73
|
-
// if (n <= 1) {
|
|
74
|
-
// return Decimal.one;
|
|
75
|
-
// } else {
|
|
76
|
-
// let result = 1;
|
|
77
|
-
// for (let i = 2; i <= n; i++) {
|
|
78
|
-
// result *= i;
|
|
79
|
-
// }
|
|
80
|
-
// return Decimal.createInt(result);
|
|
81
|
-
// }
|
|
82
|
-
// }
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* 定点数计算
|
|
86
|
-
*/
|
|
87
|
-
export class Decimal {
|
|
88
|
-
static copy(other: Decimal) {
|
|
89
|
-
return new Decimal().copy(other);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
static createInt(value: IntNumber) {
|
|
93
|
-
return new Decimal().setInt(value);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
static createFloat(value: string) {
|
|
97
|
-
return new Decimal().setFloat(value);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
static create(sign: DecimalSign, v1: IntNumber, v2: IntNumber) {
|
|
101
|
-
return new Decimal().set(sign, v1, v2);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* 精确度保留n位小数点, 默认是8。
|
|
106
|
-
* @description 注意整数与小数部分长度和不要超过16位,并且整数位大小不要超过「9 * Math.pow(10, 15-n)」,否则运算过程中会出现大整数导致的精度丢失。
|
|
107
|
-
*/
|
|
108
|
-
static set accuracy(value: IntNumber) {
|
|
109
|
-
DotLen = Math.max(Math.floor(value), 1);
|
|
110
|
-
Scale = Math.pow(10, DotLen);
|
|
111
|
-
Scale_L = Math.pow(10, DotLen - 1);
|
|
112
|
-
PI_Decimal.setFloat('3.141592653589793');
|
|
113
|
-
PI_HALF_Decimal.setFloat('1.5707963267948966');
|
|
114
|
-
Deg_Rad_Decimal.setFloat('0.017453292519943');
|
|
115
|
-
Rad_Deg_Decimal.setFloat('57.29577951308232');
|
|
116
|
-
}
|
|
117
|
-
static get accuracy() {
|
|
118
|
-
return DotLen;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* 180度对应的弧度值 (不要修改此值)
|
|
123
|
-
*/
|
|
124
|
-
static get PI() {
|
|
125
|
-
return PI_Decimal;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* 180度的一半(90度)对应的弧度值 (不要修改此值)
|
|
130
|
-
*/
|
|
131
|
-
static get PI_HALF() {
|
|
132
|
-
return PI_HALF_Decimal;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* 1度对应的弧度值 (不要修改此值)
|
|
137
|
-
*/
|
|
138
|
-
static get DEG_TO_RAD() {
|
|
139
|
-
return Deg_Rad_Decimal;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* 1弧度对应的角度值 (不要修改此值)
|
|
144
|
-
*/
|
|
145
|
-
static get RAD_TO_DEG() {
|
|
146
|
-
return Rad_Deg_Decimal;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 0
|
|
151
|
-
*/
|
|
152
|
-
static get zero() {
|
|
153
|
-
return new Decimal();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* 0 (不要修改此值)
|
|
158
|
-
*/
|
|
159
|
-
static get ZERO() {
|
|
160
|
-
Zero_Decimal.sign = 1;
|
|
161
|
-
Zero_Decimal.v1 = 0;
|
|
162
|
-
Zero_Decimal.v2 = 0;
|
|
163
|
-
return Zero_Decimal;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* 1
|
|
168
|
-
*/
|
|
169
|
-
static get one() {
|
|
170
|
-
return Decimal.createInt(1);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* 1 (不要修改此值)
|
|
175
|
-
*/
|
|
176
|
-
static get ONE() {
|
|
177
|
-
One_Decimal.sign = 1;
|
|
178
|
-
One_Decimal.v1 = 1;
|
|
179
|
-
One_Decimal.v2 = 0;
|
|
180
|
-
return One_Decimal;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* 2
|
|
185
|
-
*/
|
|
186
|
-
static get two() {
|
|
187
|
-
return Decimal.createInt(2);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* 2 (不要修改此值)
|
|
192
|
-
*/
|
|
193
|
-
static get TWO() {
|
|
194
|
-
Two_Decimal.sign = 1;
|
|
195
|
-
Two_Decimal.v1 = 2;
|
|
196
|
-
Two_Decimal.v2 = 0;
|
|
197
|
-
return Two_Decimal;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* -1
|
|
202
|
-
*/
|
|
203
|
-
static get () {
|
|
204
|
-
return Decimal.createInt(-1);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* -1 (不要修改此值)
|
|
209
|
-
*/
|
|
210
|
-
static get MINUS() {
|
|
211
|
-
Minus_Decimal.sign = -1;
|
|
212
|
-
Minus_Decimal.v1 = 1;
|
|
213
|
-
Minus_Decimal.v2 = 0;
|
|
214
|
-
return Minus_Decimal;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* NaN
|
|
219
|
-
*/
|
|
220
|
-
static get NaN() {
|
|
221
|
-
return Decimal.create(1, Number.NaN, Number.NaN);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* 取较大
|
|
226
|
-
*/
|
|
227
|
-
static max(...args: Decimal[]): Decimal {
|
|
228
|
-
let max = args[0];
|
|
229
|
-
for (let index = 1; index < args.length; index++) {
|
|
230
|
-
const num = args[index];
|
|
231
|
-
if (num.GT(max)) {
|
|
232
|
-
max = num;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return max;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* 取较小
|
|
240
|
-
*/
|
|
241
|
-
static min(...args: Decimal[]): Decimal {
|
|
242
|
-
let min = args[0];
|
|
243
|
-
for (let index = 1; index < args.length; index++) {
|
|
244
|
-
const num = args[index];
|
|
245
|
-
if (num.LT(min)) {
|
|
246
|
-
min = num;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return min;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* 弧度转角度
|
|
254
|
-
*/
|
|
255
|
-
static radiansToDegrees(out: Decimal, radians: Decimal) {
|
|
256
|
-
return out.copy(radians).mul(this.RAD_TO_DEG);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* 角度转弧度
|
|
261
|
-
* @param out 输出结果
|
|
262
|
-
* @param degrees 角度
|
|
263
|
-
* @returns 结果
|
|
264
|
-
*/
|
|
265
|
-
static degreesToRadians(out: Decimal, degrees: Decimal) {
|
|
266
|
-
return out.copy(degrees).mul(this.DEG_TO_RAD);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* 正弦函数
|
|
271
|
-
*/
|
|
272
|
-
static sin(out: Decimal, angle: Decimal): Decimal {
|
|
273
|
-
// // 预计算阶乘
|
|
274
|
-
// if (Factorial_Decimals.length === 0) {
|
|
275
|
-
// for (let i = 0, result = 1; i < 21; i++) {
|
|
276
|
-
// result *= i + 1;
|
|
277
|
-
// Factorial_Decimals.push(Decimal.createInt(result));
|
|
278
|
-
// }
|
|
279
|
-
// }
|
|
280
|
-
|
|
281
|
-
// // 将角度转换为弧度
|
|
282
|
-
// const radius = TempB1.copy(angle).mod(TempB2.setInt(360)).mul(this.DEG_TO_RAD);
|
|
283
|
-
|
|
284
|
-
// // 迭代次数
|
|
285
|
-
// const iterations = 10;// 最大不能超过10,不然会产生超大整数(科学计数法)
|
|
286
|
-
// const result = out.copy(this.ZERO);
|
|
287
|
-
|
|
288
|
-
// // sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
|
|
289
|
-
// for (let i = 0; i <= iterations; i++) {
|
|
290
|
-
// const exponent = 2 * i + 1;
|
|
291
|
-
// const numerator = TempB2.copy(radius).pow(exponent);
|
|
292
|
-
// const denominator = Factorial_Decimals[exponent - 1] || factorial(exponent);
|
|
293
|
-
// const term = numerator.div(denominator).mul((i % 2 === 0) ? this.ONE : this.MINUS);
|
|
294
|
-
// result.add(term);
|
|
295
|
-
// }
|
|
296
|
-
|
|
297
|
-
// return result;
|
|
298
|
-
return this.cos(out, TempB1.copy(angle).addInt(90)).negative();
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* 余弦函数
|
|
303
|
-
*/
|
|
304
|
-
static cos(out: Decimal, angle: Decimal): Decimal {
|
|
305
|
-
// // 预计算阶乘
|
|
306
|
-
// if (Factorial_Decimals.length === 0) {
|
|
307
|
-
// for (let i = 0, result = 1; i < 21; i++) {
|
|
308
|
-
// result *= i + 1;
|
|
309
|
-
// Factorial_Decimals.push(Decimal.createInt(result));
|
|
310
|
-
// }
|
|
311
|
-
// }
|
|
312
|
-
|
|
313
|
-
// // 将角度转换为弧度
|
|
314
|
-
// const radius = TempB1.copy(angle).mod(TempB2.setInt(360)).mul(this.DEG_TO_RAD);
|
|
315
|
-
|
|
316
|
-
// // 迭代次数
|
|
317
|
-
// const iterations = 10;// 最大不能超过10,不然会产生超大整数(科学计数法)
|
|
318
|
-
// const result = out.copy(this.ZERO);
|
|
319
|
-
|
|
320
|
-
// // sin(x) = x - x^2/2! + x^4/4! - x^6/6! + ...
|
|
321
|
-
// for (let i = 0; i <= iterations; i++) {
|
|
322
|
-
// const exponent = 2 * i;
|
|
323
|
-
// const numerator = TempB2.copy(radius).pow(exponent);
|
|
324
|
-
// const denominator = Factorial_Decimals[exponent - 1] || factorial(exponent);
|
|
325
|
-
// const term = numerator.div(denominator).mul((i % 2 === 0) ? this.ONE : this.MINUS);
|
|
326
|
-
// result.add(term);
|
|
327
|
-
// }
|
|
328
|
-
|
|
329
|
-
// return result;
|
|
330
|
-
|
|
331
|
-
// 将角度转换为弧度
|
|
332
|
-
const radius = TempB1.copy(angle).modInt(360).mul(this.DEG_TO_RAD);
|
|
333
|
-
|
|
334
|
-
// 迭代次数
|
|
335
|
-
const iterations = 9;
|
|
336
|
-
const result = out.copy(this.ONE);
|
|
337
|
-
|
|
338
|
-
const term = TempB2.setInt(1);
|
|
339
|
-
for (let i = 1; i <= iterations; i++) {
|
|
340
|
-
term.mul(radius).mul(radius).negative().divInt((2 * i - 1) * (2 * i));
|
|
341
|
-
result.add(term);
|
|
342
|
-
}
|
|
343
|
-
return result;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* 正切函数
|
|
348
|
-
*/
|
|
349
|
-
static tan(out: Decimal, angle: Decimal): Decimal {
|
|
350
|
-
const sinValue = this.sin(out, angle);
|
|
351
|
-
const cosValue = this.cos(TempB3, angle);
|
|
352
|
-
return sinValue.div(cosValue);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* 计算反正弦
|
|
357
|
-
*/
|
|
358
|
-
static asin(out: Decimal, value: Decimal) {
|
|
359
|
-
// atan(a / Math.sqrt(1 - a * a));
|
|
360
|
-
TempB1.copy(value).pow().negative().add(this.ONE).sqrt();
|
|
361
|
-
TempB2.copy(value).div(TempB1);
|
|
362
|
-
return this.atan(out, TempB2);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* 计算反余弦
|
|
367
|
-
*/
|
|
368
|
-
static acos(out: Decimal, value: Decimal) {
|
|
369
|
-
if (value.LT(this.MINUS) || value.GT(this.ONE)) {
|
|
370
|
-
return out.set(1, Number.NaN, Number.NaN);
|
|
371
|
-
}
|
|
372
|
-
if (value.EQ(this.ONE)) {
|
|
373
|
-
return out.set(1, 0, 0);
|
|
374
|
-
}
|
|
375
|
-
if (value.EQ(this.ZERO)) {
|
|
376
|
-
return out.set(1, 90, 0);
|
|
377
|
-
}
|
|
378
|
-
if (value.EQ(this.MINUS)) {
|
|
379
|
-
return out.set(1, 180, 0);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// function modp(a, b) {
|
|
383
|
-
// return a - Math.floor(a / b) * b;
|
|
384
|
-
// }
|
|
385
|
-
// modp(atan(Math.sqrt(1 - a * a) / a), PI)
|
|
386
|
-
TempB1.copy(value).pow().negative().add(this.ONE).sqrt().div(value);
|
|
387
|
-
this.atan(out, TempB1).modInt(180);
|
|
388
|
-
if (out.isNegative()) {
|
|
389
|
-
return out.addInt(180);
|
|
390
|
-
}
|
|
391
|
-
return out;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* 计算反正切
|
|
396
|
-
*/
|
|
397
|
-
static atan(out: Decimal, value: Decimal) {
|
|
398
|
-
if (value.EQ(this.ZERO)) {
|
|
399
|
-
return out.copy(this.ZERO);
|
|
400
|
-
}
|
|
401
|
-
if (value.v1 === 1 && value.v2 === 0) {
|
|
402
|
-
return out.set(value.sign, 45, 0);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
let sign = 1;
|
|
406
|
-
let swap = false;
|
|
407
|
-
let correction = false;
|
|
408
|
-
|
|
409
|
-
if (out.copy(value).isNegative()) {
|
|
410
|
-
sign = -1;
|
|
411
|
-
out.negative();
|
|
412
|
-
}
|
|
413
|
-
if (out.GT(this.ONE)) {
|
|
414
|
-
out.reciprocal();
|
|
415
|
-
swap = true;
|
|
416
|
-
}
|
|
417
|
-
if (out.GTFloat('0.26794919')) {
|
|
418
|
-
const SQRT3 = TempC1.setFloat('1.7320508075688772');// √3
|
|
419
|
-
TempC2.copy(out).add(SQRT3);
|
|
420
|
-
out.mul(SQRT3).sub(this.ONE).div(TempC2);
|
|
421
|
-
correction = true;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
TempC1.copy(out)
|
|
425
|
-
.sub(TempC2.setFloat('0.3333333342477778').mul(TempC3.copy(out).pow(3)))
|
|
426
|
-
.add(TempC2.setFloat('0.19999967200053792').mul(TempC3.mul(out).mul(out)))
|
|
427
|
-
.add(TempC2.setFloat('0.11108765927193148').mul(TempC3.mul(out)))
|
|
428
|
-
.sub(TempC2.setFloat('0.14285489799446008').mul(TempC3.mul(out)))
|
|
429
|
-
.sub(TempC2.setFloat('0.0849762066621346').mul(TempC3.mul(out)));
|
|
430
|
-
out.copy(TempC1);
|
|
431
|
-
|
|
432
|
-
if (correction) {
|
|
433
|
-
out.addFloat('0.5235987755982988');// PI / 6
|
|
434
|
-
}
|
|
435
|
-
if (swap) {
|
|
436
|
-
out.sub(this.PI_HALF).negative();
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
out.sign *= sign;
|
|
440
|
-
|
|
441
|
-
return out.mul(this.RAD_TO_DEG);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* 计算反正切,给定 x 和 y 的值
|
|
446
|
-
*/
|
|
447
|
-
static atan2(out: Decimal, y: Decimal, x: Decimal) {
|
|
448
|
-
if (x.EQ(this.ZERO) && y.EQ(this.ZERO)) {
|
|
449
|
-
return out.copy(this.ZERO);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (x.GT(this.ZERO)) {
|
|
453
|
-
return this.atan(out, TempD1.copy(y).div(x));
|
|
454
|
-
} else if (x.LT(this.ZERO) && y.GE(this.ZERO)) {
|
|
455
|
-
return this.atan(out, TempD1.copy(y).div(x)).addInt(180);
|
|
456
|
-
} else if (x.LT(this.ZERO) && y.LT(this.ZERO)) {
|
|
457
|
-
return this.atan(out, TempD1.copy(y).div(x)).subInt(180);
|
|
458
|
-
} else if (x.EQ(this.ZERO) && y.GT(this.ZERO)) {
|
|
459
|
-
return out.setInt(90);
|
|
460
|
-
} else {
|
|
461
|
-
return out.setInt(-90);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// 符号位
|
|
466
|
-
private _sign: DecimalSign = 1;
|
|
467
|
-
public get sign(): DecimalSign {
|
|
468
|
-
return this._sign;
|
|
469
|
-
}
|
|
470
|
-
private set sign(value: DecimalSign) {
|
|
471
|
-
this._sign = value;
|
|
472
|
-
}
|
|
473
|
-
// 商
|
|
474
|
-
private _v1: IntNumber = 0;
|
|
475
|
-
public get v1(): IntNumber {
|
|
476
|
-
return this._v1;
|
|
477
|
-
}
|
|
478
|
-
private set v1(value: IntNumber) {
|
|
479
|
-
this._v1 = value;
|
|
480
|
-
}
|
|
481
|
-
// 余
|
|
482
|
-
private _v2: IntNumber = 0;
|
|
483
|
-
public get v2(): IntNumber {
|
|
484
|
-
return this._v2;
|
|
485
|
-
}
|
|
486
|
-
private set v2(value: IntNumber) {
|
|
487
|
-
this._v2 = value;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/** 可选 observer。默认 null,算法 scratch Decimal 不承担观察成本。 */
|
|
491
|
-
private __observer: IDecimalMutationObserver | null = null;
|
|
492
|
-
/** 嵌套 mutation 深度,用于 batch 合并多次原地修改。 */
|
|
493
|
-
private __mutationDepth = 0;
|
|
494
|
-
/** batch 内是否发生过实际数值变化。 */
|
|
495
|
-
private __mutationPending = false;
|
|
496
|
-
/** 静默写入深度。大批量业务写屏障可用 setSilent/copySilent 后手动 markDirty。 */
|
|
497
|
-
private __silentDepth = 0;
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* 绑定或解绑 Decimal mutation observer。
|
|
501
|
-
* 仅 @EcsObservedDecimal 管理的组件字段需要绑定;普通 Decimal、SAT/MTV 临时值不要绑定。
|
|
502
|
-
*/
|
|
503
|
-
public bindMutationObserver(observer: IDecimalMutationObserver | null): this {
|
|
504
|
-
this.__observer = observer;
|
|
505
|
-
if (!observer) {
|
|
506
|
-
this.__mutationDepth = 0;
|
|
507
|
-
this.__mutationPending = false;
|
|
508
|
-
}
|
|
509
|
-
return this;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
/** 开始合并多次 Decimal 修改,直到 endMutationBatch 才通知一次 observer。 */
|
|
513
|
-
public beginMutationBatch(): this {
|
|
514
|
-
if (this.__observer && this.__silentDepth === 0) {
|
|
515
|
-
this.__mutationDepth++;
|
|
516
|
-
}
|
|
517
|
-
return this;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
/** 结束 batch;如果期间值发生变化且已回到最外层,则通知一次 observer。 */
|
|
521
|
-
public endMutationBatch(): this {
|
|
522
|
-
if (this.__observer && this.__silentDepth === 0 && this.__mutationDepth > 0) {
|
|
523
|
-
this.__mutationDepth--;
|
|
524
|
-
this.flushMutationObserverIfReady();
|
|
525
|
-
}
|
|
526
|
-
return this;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
/** 用函数作用域包住 batch,避免异常时忘记 endMutationBatch。 */
|
|
530
|
-
public runMutationBatch<T>(action: () => T): T {
|
|
531
|
-
this.beginMutationBatch();
|
|
532
|
-
try {
|
|
533
|
-
return action();
|
|
534
|
-
} finally {
|
|
535
|
-
this.endMutationBatch();
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
/** 静默执行 Decimal 修改,不通知 observer。适合业务写屏障合并后手动 markDirty。 */
|
|
540
|
-
public runSilentMutation<T>(action: () => T): T {
|
|
541
|
-
this.__silentDepth++;
|
|
542
|
-
try {
|
|
543
|
-
return action();
|
|
544
|
-
} finally {
|
|
545
|
-
this.__silentDepth--;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
/** 静默 set,不触发 Decimal observer。 */
|
|
550
|
-
public setSilent(sign: DecimalSign = 1, v1: IntNumber = 0, v2: IntNumber = 0): this {
|
|
551
|
-
return this.runSilentMutation(() => this.set(sign, v1, v2));
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
/** 静默 copy,不触发 Decimal observer。 */
|
|
555
|
-
public copySilent(other: Decimal): this {
|
|
556
|
-
return this.runSilentMutation(() => this.copy(other));
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
private static compareAbs(a: Decimal, b: Decimal): -1 | 0 | 1 {
|
|
560
|
-
if (a.v1 > b.v1) return 1;
|
|
561
|
-
if (a.v1 < b.v1) return -1;
|
|
562
|
-
if (a.v2 > b.v2) return 1;
|
|
563
|
-
if (a.v2 < b.v2) return -1;
|
|
564
|
-
return 0;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
private static compareSigned(a: Decimal, b: Decimal): -1 | 0 | 1 {
|
|
568
|
-
if (a.sign !== b.sign) {
|
|
569
|
-
return a.sign > b.sign ? 1 : -1;
|
|
570
|
-
}
|
|
571
|
-
const cmp = Decimal.compareAbs(a, b);
|
|
572
|
-
return a.sign === 1 ? cmp : (cmp === 0 ? 0 : (cmp > 0 ? -1 : 1));
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
private normalizeZero() {
|
|
576
|
-
if (this.v1 === 0 && this.v2 === 0) {
|
|
577
|
-
this.sign = 1;
|
|
578
|
-
}
|
|
579
|
-
return this;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
private snapshot(): DecimalSnapshot {
|
|
583
|
-
return {
|
|
584
|
-
sign: this.sign,
|
|
585
|
-
v1: this.v1,
|
|
586
|
-
v2: this.v2,
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
private changedSince(snapshot: DecimalSnapshot): boolean {
|
|
591
|
-
return !Object.is(this.sign, snapshot.sign)
|
|
592
|
-
|| !Object.is(this.v1, snapshot.v1)
|
|
593
|
-
|| !Object.is(this.v2, snapshot.v2);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
/** 所有会原地修改 Decimal 的 public 方法都应通过这里包裹,确保值变才通知。 */
|
|
597
|
-
private runMutation<T>(action: () => T): T {
|
|
598
|
-
const observer = this.__observer;
|
|
599
|
-
if (!observer || this.__silentDepth > 0) {
|
|
600
|
-
return action();
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
const before = this.snapshot();
|
|
604
|
-
this.__mutationDepth++;
|
|
605
|
-
try {
|
|
606
|
-
return action();
|
|
607
|
-
} finally {
|
|
608
|
-
if (this.changedSince(before)) {
|
|
609
|
-
this.__mutationPending = true;
|
|
610
|
-
}
|
|
611
|
-
this.__mutationDepth--;
|
|
612
|
-
this.flushMutationObserverIfReady();
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
/** batch/silent 状态允许时,把一次已合并的 mutation 通知给 observer。 */
|
|
617
|
-
private flushMutationObserverIfReady(): void {
|
|
618
|
-
if (this.__mutationDepth !== 0 || !this.__mutationPending || this.__silentDepth > 0) return;
|
|
619
|
-
|
|
620
|
-
this.__mutationPending = false;
|
|
621
|
-
const observer = this.__observer;
|
|
622
|
-
if (observer) {
|
|
623
|
-
observer.onDecimalMutated(this);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
private setAbsSub(aSign: DecimalSign, aV1: IntNumber, aV2: IntNumber, bV1: IntNumber, bV2: IntNumber) {
|
|
628
|
-
let v1 = aV1 - bV1;
|
|
629
|
-
let v2 = aV2 - bV2;
|
|
630
|
-
if (v2 < 0) {
|
|
631
|
-
v2 += Scale;
|
|
632
|
-
v1 -= 1;
|
|
633
|
-
}
|
|
634
|
-
this.sign = aSign;
|
|
635
|
-
this.v1 = v1;
|
|
636
|
-
this.v2 = v2;
|
|
637
|
-
return this.normalizeZero();
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
private setAbsAdd(sign: DecimalSign, aV1: IntNumber, aV2: IntNumber, bV1: IntNumber, bV2: IntNumber) {
|
|
641
|
-
let v1 = aV1 + bV1;
|
|
642
|
-
let v2 = aV2 + bV2;
|
|
643
|
-
if (v2 >= Scale) {
|
|
644
|
-
v2 -= Scale;
|
|
645
|
-
v1 += 1;
|
|
646
|
-
}
|
|
647
|
-
this.sign = sign;
|
|
648
|
-
this.v1 = v1;
|
|
649
|
-
this.v2 = v2;
|
|
650
|
-
return this.normalizeZero();
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
private setFromRawBigInt(raw: any) {
|
|
654
|
-
if (!BigIntCtor) {
|
|
655
|
-
return this.set(1, Number.NaN, Number.NaN);
|
|
656
|
-
}
|
|
657
|
-
const zero = BigIntCtor(0);
|
|
658
|
-
const scale = BigIntCtor(Scale);
|
|
659
|
-
let sign: DecimalSign = 1;
|
|
660
|
-
if (raw < zero) {
|
|
661
|
-
sign = -1;
|
|
662
|
-
raw = -raw;
|
|
663
|
-
}
|
|
664
|
-
this.sign = sign;
|
|
665
|
-
this.v1 = Number(raw / scale);
|
|
666
|
-
this.v2 = Number(raw % scale);
|
|
667
|
-
return this.normalizeZero();
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
/**
|
|
671
|
-
* 用于等号赋值
|
|
672
|
-
* @example
|
|
673
|
-
* const a = new Decimal('1');
|
|
674
|
-
* const b = new Decimal('10');
|
|
675
|
-
* a.value = b;
|
|
676
|
-
*/
|
|
677
|
-
public set value(other: Decimal) {
|
|
678
|
-
this.runMutation(() => {
|
|
679
|
-
this.sign = other.sign;
|
|
680
|
-
this.v1 = other.v1;
|
|
681
|
-
this.v2 = other.v2;
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
/**
|
|
686
|
-
* 传入字符串数字
|
|
687
|
-
* @param value 字符串数字(不支持科学计数)
|
|
688
|
-
*/
|
|
689
|
-
constructor(value: string);
|
|
690
|
-
/**
|
|
691
|
-
* 构造 0
|
|
692
|
-
*/
|
|
693
|
-
constructor();
|
|
694
|
-
constructor(value?: string) {
|
|
695
|
-
this.setFloat(value);
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
/**
|
|
699
|
-
* 设置, 默认为0
|
|
700
|
-
*/
|
|
701
|
-
set(sign: DecimalSign = 1, v1: IntNumber = 0, v2: IntNumber = 0) {
|
|
702
|
-
return this.runMutation(() => {
|
|
703
|
-
this.sign = sign;
|
|
704
|
-
this.v1 = v1;
|
|
705
|
-
this.v2 = v2;
|
|
706
|
-
return this;
|
|
707
|
-
});
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
/**
|
|
711
|
-
* 通过float字符串设置, 默认为0
|
|
712
|
-
*/
|
|
713
|
-
setFloat(value: string = '') {
|
|
714
|
-
return this.runMutation(() => {
|
|
715
|
-
if (!value) {
|
|
716
|
-
this.sign = 1;
|
|
717
|
-
this.v1 = 0;
|
|
718
|
-
this.v2 = 0;
|
|
719
|
-
return this;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
// 符号位
|
|
723
|
-
this.sign = value[0] === '-' ? -1 : 1;
|
|
724
|
-
|
|
725
|
-
// 分割整数与小数
|
|
726
|
-
const strArr = value.split('.');
|
|
727
|
-
|
|
728
|
-
// 整数
|
|
729
|
-
this.v1 = Math.abs(parseInt(strArr[0] || '0'));
|
|
730
|
-
|
|
731
|
-
// 小数
|
|
732
|
-
this.v2 = strArr.length === 1 ? 0 : parseInt(decimalStr(strArr[1]));
|
|
733
|
-
|
|
734
|
-
if (this.v1 === 0 && this.v2 === 0) {
|
|
735
|
-
this.sign = 1;
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
return this;
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* 通过int设置, 默认为0
|
|
744
|
-
*/
|
|
745
|
-
setInt(value: IntNumber = 0) {
|
|
746
|
-
return this.runMutation(() => {
|
|
747
|
-
if (DEV) {
|
|
748
|
-
if (value !== Math.floor(value)) {
|
|
749
|
-
console.error('setInt: 参数必须是整数,而不应该是', value);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
if (value < 0) {
|
|
753
|
-
this.sign = -1;
|
|
754
|
-
this.v1 = Math.floor(-value);
|
|
755
|
-
this.v2 = 0;
|
|
756
|
-
} else {
|
|
757
|
-
this.sign = 1;
|
|
758
|
-
this.v1 = Math.floor(value);
|
|
759
|
-
this.v2 = 0;
|
|
760
|
-
}
|
|
761
|
-
return this;
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
/**
|
|
766
|
-
* 通过其他Decimal设置
|
|
767
|
-
*/
|
|
768
|
-
copy(other: Decimal) {
|
|
769
|
-
return this.runMutation(() => {
|
|
770
|
-
this.sign = other.sign;
|
|
771
|
-
this.v1 = other.v1;
|
|
772
|
-
this.v2 = other.v2;
|
|
773
|
-
return this;
|
|
774
|
-
});
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
/**
|
|
778
|
-
* 转为浮点数
|
|
779
|
-
* @param strict 严格模式,默认关闭。开启后额外消耗性能,避免定点数转小数时出现精度问题。
|
|
780
|
-
*/
|
|
781
|
-
toNumber(strict = false): number {
|
|
782
|
-
if (strict) {
|
|
783
|
-
return parseFloat(this.toString());
|
|
784
|
-
}
|
|
785
|
-
return this.sign * (this.v1 + this.v2 / Scale);
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
/**
|
|
789
|
-
* 转为字符串
|
|
790
|
-
*/
|
|
791
|
-
toString(): string {
|
|
792
|
-
if (this.sign === 1) {
|
|
793
|
-
return this.v1.toString() + '.' + '0'.repeat(DotLen - this.v2.toString().length) + this.v2;
|
|
794
|
-
}
|
|
795
|
-
return '-' + this.v1.toString() + '.' + '0'.repeat(DotLen - this.v2.toString().length) + this.v2;
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
/**
|
|
799
|
-
* 转为大整数
|
|
800
|
-
*/
|
|
801
|
-
toBigInt(): IntNumber {
|
|
802
|
-
return this.sign * (this.v1 * Scale + this.v2);
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
/**
|
|
806
|
-
* 是否为0
|
|
807
|
-
*/
|
|
808
|
-
isZero() {
|
|
809
|
-
return this.v1 === 0 && this.v2 === 0;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
* 是否是负数
|
|
814
|
-
*/
|
|
815
|
-
isNegative() {
|
|
816
|
-
return this.sign < 0 && (this.v1 > 0 || this.v2 > 0);
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
/**
|
|
820
|
-
* 是否是NaN
|
|
821
|
-
*/
|
|
822
|
-
isNaN() {
|
|
823
|
-
return Number.isNaN(this.v1) || Number.isNaN(this.v2);
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
/**
|
|
827
|
-
* 克隆
|
|
828
|
-
*/
|
|
829
|
-
clone(): Decimal {
|
|
830
|
-
return new Decimal().copy(this);
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
/**
|
|
834
|
-
* 向下取整
|
|
835
|
-
*/
|
|
836
|
-
floor() {
|
|
837
|
-
return this.runMutation(() => {
|
|
838
|
-
if (this.v2 > 0 && this.sign === -1) {
|
|
839
|
-
this.v1 += 1;
|
|
840
|
-
}
|
|
841
|
-
this.v2 = 0;
|
|
842
|
-
return this;
|
|
843
|
-
});
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
/**
|
|
847
|
-
* 向上取整
|
|
848
|
-
*/
|
|
849
|
-
ceil() {
|
|
850
|
-
return this.runMutation(() => {
|
|
851
|
-
if (this.v2 > 0 && this.sign === 1) {
|
|
852
|
-
this.v1 += 1;
|
|
853
|
-
}
|
|
854
|
-
this.v2 = 0;
|
|
855
|
-
if (this.v1 === 0) {
|
|
856
|
-
this.sign = 1;
|
|
857
|
-
}
|
|
858
|
-
return this;
|
|
859
|
-
});
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
/**
|
|
863
|
-
* 四舍五入
|
|
864
|
-
*/
|
|
865
|
-
round() {
|
|
866
|
-
return this.runMutation(() => {
|
|
867
|
-
if (this.v2 > Scale >> 1) {
|
|
868
|
-
this.v1 += 1;
|
|
869
|
-
}
|
|
870
|
-
this.v2 = 0;
|
|
871
|
-
if (this.v1 === 0) {
|
|
872
|
-
this.sign = 1;
|
|
873
|
-
}
|
|
874
|
-
return this;
|
|
875
|
-
});
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
/**
|
|
879
|
-
* 绝对值
|
|
880
|
-
*/
|
|
881
|
-
abs(): Decimal {
|
|
882
|
-
return this.runMutation(() => {
|
|
883
|
-
this.sign = 1;
|
|
884
|
-
return this;
|
|
885
|
-
});
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
/**
|
|
889
|
-
* @deprecated 使用negative代替
|
|
890
|
-
*/
|
|
891
|
-
reverse(): Decimal {
|
|
892
|
-
return this.runMutation(() => {
|
|
893
|
-
this.sign *= -1;
|
|
894
|
-
return this;
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
/**
|
|
899
|
-
* 相反数
|
|
900
|
-
*/
|
|
901
|
-
negative(): Decimal {
|
|
902
|
-
return this.runMutation(() => {
|
|
903
|
-
this.sign *= -1;
|
|
904
|
-
return this;
|
|
905
|
-
});
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
/**
|
|
909
|
-
* 倒数
|
|
910
|
-
*/
|
|
911
|
-
reciprocal(): Decimal {
|
|
912
|
-
return this.runMutation(() => this.copy(Decimal.ONE.div(this)));
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
/**
|
|
916
|
-
* 加法
|
|
917
|
-
* @param other
|
|
918
|
-
*/
|
|
919
|
-
add(other: Decimal): Decimal {
|
|
920
|
-
return this.runMutation(() => {
|
|
921
|
-
if (this.sign === other.sign) {
|
|
922
|
-
return this.setAbsAdd(this.sign, this.v1, this.v2, other.v1, other.v2);
|
|
923
|
-
}
|
|
924
|
-
const cmp = Decimal.compareAbs(this, other);
|
|
925
|
-
if (cmp === 0) {
|
|
926
|
-
return this.set();
|
|
927
|
-
}
|
|
928
|
-
if (cmp > 0) {
|
|
929
|
-
return this.setAbsSub(this.sign, this.v1, this.v2, other.v1, other.v2);
|
|
930
|
-
}
|
|
931
|
-
return this.setAbsSub(other.sign, other.v1, other.v2, this.v1, this.v2);
|
|
932
|
-
});
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
/**
|
|
936
|
-
* 加法
|
|
937
|
-
* @param other
|
|
938
|
-
*/
|
|
939
|
-
addInt(other: IntNumber): Decimal {
|
|
940
|
-
return this.add(Temp.setInt(other));
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
/**
|
|
944
|
-
* 加法
|
|
945
|
-
* @param other
|
|
946
|
-
*/
|
|
947
|
-
addFloat(other: string): Decimal {
|
|
948
|
-
return this.add(Temp.setFloat(other));
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
/**
|
|
952
|
-
* 减法
|
|
953
|
-
* @param other
|
|
954
|
-
*/
|
|
955
|
-
sub(other: Decimal): Decimal {
|
|
956
|
-
return this.runMutation(() => {
|
|
957
|
-
if (this.sign !== other.sign) {
|
|
958
|
-
return this.setAbsAdd(this.sign, this.v1, this.v2, other.v1, other.v2);
|
|
959
|
-
}
|
|
960
|
-
const cmp = Decimal.compareAbs(this, other);
|
|
961
|
-
if (cmp === 0) {
|
|
962
|
-
return this.set();
|
|
963
|
-
}
|
|
964
|
-
if (cmp > 0) {
|
|
965
|
-
return this.setAbsSub(this.sign, this.v1, this.v2, other.v1, other.v2);
|
|
966
|
-
}
|
|
967
|
-
return this.setAbsSub(this.sign === 1 ? -1 : 1, other.v1, other.v2, this.v1, this.v2);
|
|
968
|
-
});
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
/**
|
|
972
|
-
* 减法
|
|
973
|
-
* @param other
|
|
974
|
-
*/
|
|
975
|
-
subInt(other: IntNumber): Decimal {
|
|
976
|
-
return this.sub(Temp.setInt(other));
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
/**
|
|
980
|
-
* 减法
|
|
981
|
-
* @param other
|
|
982
|
-
*/
|
|
983
|
-
subFloat(other: string): Decimal {
|
|
984
|
-
return this.sub(Temp.setFloat(other));
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
/**
|
|
988
|
-
* 乘法
|
|
989
|
-
* @param other
|
|
990
|
-
*/
|
|
991
|
-
mul(other: Decimal): Decimal {
|
|
992
|
-
return this.runMutation(() => {
|
|
993
|
-
// 保持 8 位小数语义:floor((rawA * rawB) / Scale)。
|
|
994
|
-
// 不能直接 rawA * rawB,会超过 JS 安全整数;这里按整数位/小数位拆分累计。
|
|
995
|
-
const sign: DecimalSign = this.sign === other.sign ? 1 : -1;
|
|
996
|
-
let v1 = this.v1 * other.v1;
|
|
997
|
-
let v2 = 0;
|
|
998
|
-
|
|
999
|
-
let part = this.v1 * other.v2;
|
|
1000
|
-
v1 += intDiv(part, Scale);
|
|
1001
|
-
v2 += intMod(part, Scale);
|
|
1002
|
-
if (v2 >= Scale) {
|
|
1003
|
-
v1 += intDiv(v2, Scale);
|
|
1004
|
-
v2 = intMod(v2, Scale);
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
part = this.v2 * other.v1;
|
|
1008
|
-
v1 += intDiv(part, Scale);
|
|
1009
|
-
v2 += intMod(part, Scale);
|
|
1010
|
-
if (v2 >= Scale) {
|
|
1011
|
-
v1 += intDiv(v2, Scale);
|
|
1012
|
-
v2 = intMod(v2, Scale);
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
v2 += mulFractionToScaledFloor(this.v2, other.v2);
|
|
1016
|
-
if (v2 >= Scale) {
|
|
1017
|
-
v1 += intDiv(v2, Scale);
|
|
1018
|
-
v2 = intMod(v2, Scale);
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
this.sign = sign;
|
|
1022
|
-
this.v1 = v1;
|
|
1023
|
-
this.v2 = v2;
|
|
1024
|
-
return this.normalizeZero();
|
|
1025
|
-
});
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
/**
|
|
1029
|
-
* 乘法
|
|
1030
|
-
* @param other
|
|
1031
|
-
*/
|
|
1032
|
-
mulInt(other: IntNumber): Decimal {
|
|
1033
|
-
return this.mul(Temp.setInt(other));
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
/**
|
|
1037
|
-
* 乘法
|
|
1038
|
-
* @param other
|
|
1039
|
-
*/
|
|
1040
|
-
mulFloat(other: string): Decimal {
|
|
1041
|
-
return this.mul(Temp.setFloat(other));
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
/**
|
|
1045
|
-
* 除法
|
|
1046
|
-
* @param other
|
|
1047
|
-
*/
|
|
1048
|
-
div(other: Decimal): Decimal {
|
|
1049
|
-
return this.runMutation(() => {
|
|
1050
|
-
const down = other.v1 * Scale + other.v2;
|
|
1051
|
-
if (down === 0) {
|
|
1052
|
-
return this.set(1, Number.NaN, Number.NaN);
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
const sign: DecimalSign = this.sign === other.sign ? 1 : -1;
|
|
1056
|
-
if (BigIntCtor) {
|
|
1057
|
-
const scale = BigIntCtor(Scale);
|
|
1058
|
-
const upRaw = BigIntCtor(this.v1) * scale + BigIntCtor(this.v2);
|
|
1059
|
-
const downRaw = BigIntCtor(other.v1) * scale + BigIntCtor(other.v2);
|
|
1060
|
-
const signed = (upRaw * scale / downRaw) * BigIntCtor(sign);
|
|
1061
|
-
return this.setFromRawBigInt(signed);
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
// 兼容不支持 BigInt 的运行时:保留原分段除法语义,但不再分配 {shang, yu} 对象。
|
|
1065
|
-
const up = this.v1 * Scale + this.v2;
|
|
1066
|
-
const q1 = intDiv(up, down);
|
|
1067
|
-
const r1 = up - q1 * down;
|
|
1068
|
-
const q2 = intDiv(r1 * Scale, down);
|
|
1069
|
-
this.sign = sign;
|
|
1070
|
-
this.v1 = q1;
|
|
1071
|
-
this.v2 = q2;
|
|
1072
|
-
return this.normalizeZero();
|
|
1073
|
-
});
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
/**
|
|
1077
|
-
* 除法
|
|
1078
|
-
* @param other
|
|
1079
|
-
*/
|
|
1080
|
-
divInt(other: IntNumber): Decimal {
|
|
1081
|
-
return this.div(Temp.setInt(other));
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
/**
|
|
1085
|
-
* 除法
|
|
1086
|
-
* @param other
|
|
1087
|
-
*/
|
|
1088
|
-
divFloat(other: string): Decimal {
|
|
1089
|
-
return this.div(Temp.setFloat(other));
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
/**
|
|
1093
|
-
* 取余数
|
|
1094
|
-
* @param other
|
|
1095
|
-
*/
|
|
1096
|
-
mod(other: Decimal): Decimal {
|
|
1097
|
-
return this.runMutation(() => {
|
|
1098
|
-
const down = other.v1 * Scale + other.v2;
|
|
1099
|
-
|
|
1100
|
-
// 分母为0
|
|
1101
|
-
if (down === 0) {
|
|
1102
|
-
return this.set(1, Number.NaN, Number.NaN);
|
|
1103
|
-
}
|
|
1104
|
-
// 分子 < 分母
|
|
1105
|
-
if (Decimal.compareAbs(this, other) < 0) {
|
|
1106
|
-
return this;
|
|
1107
|
-
}
|
|
1108
|
-
// 分子 == 分母
|
|
1109
|
-
if (Decimal.compareAbs(this, other) === 0) {
|
|
1110
|
-
return this.set();
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
if (BigIntCtor) {
|
|
1114
|
-
const scale = BigIntCtor(Scale);
|
|
1115
|
-
const upRaw = BigIntCtor(this.v1) * scale + BigIntCtor(this.v2);
|
|
1116
|
-
const downRaw = BigIntCtor(other.v1) * scale + BigIntCtor(other.v2);
|
|
1117
|
-
return this.setFromRawBigInt((upRaw % downRaw) * BigIntCtor(this.sign));
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
const up = this.v1 * Scale + this.v2;
|
|
1121
|
-
const rem = intMod(up, down);
|
|
1122
|
-
this.v1 = intDiv(rem, Scale);
|
|
1123
|
-
this.v2 = intMod(rem, Scale);
|
|
1124
|
-
return this.normalizeZero();
|
|
1125
|
-
});
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
/**
|
|
1129
|
-
* 取余数
|
|
1130
|
-
* @param other
|
|
1131
|
-
*/
|
|
1132
|
-
modInt(other: IntNumber): Decimal {
|
|
1133
|
-
return this.mod(Temp.setInt(other));
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
/**
|
|
1137
|
-
* 取余数
|
|
1138
|
-
* @param other
|
|
1139
|
-
*/
|
|
1140
|
-
modFloat(other: string): Decimal {
|
|
1141
|
-
return this.mod(Temp.setFloat(other));
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
/**
|
|
1145
|
-
* n次方
|
|
1146
|
-
* @param n 整数
|
|
1147
|
-
*/
|
|
1148
|
-
pow(n: IntNumber = 2) {
|
|
1149
|
-
return this.runMutation(() => {
|
|
1150
|
-
if (n === 0) {
|
|
1151
|
-
this.sign = 1;
|
|
1152
|
-
this.v1 = 1;
|
|
1153
|
-
this.v2 = 0;
|
|
1154
|
-
} else if (n === 1) {
|
|
1155
|
-
return this;
|
|
1156
|
-
} else if (n === 2) {
|
|
1157
|
-
this.mul(TempA1.copy(this));
|
|
1158
|
-
} else if (n > 0) {
|
|
1159
|
-
const clone = TempA1.copy(this);
|
|
1160
|
-
for (let index = 1; index < n; index++) {
|
|
1161
|
-
this.mul(clone);
|
|
1162
|
-
}
|
|
1163
|
-
} else {
|
|
1164
|
-
const clone = TempA1.copy(this);
|
|
1165
|
-
this.sign = 1;
|
|
1166
|
-
this.v1 = 1;
|
|
1167
|
-
this.v2 = 0;
|
|
1168
|
-
for (let index = -1; index >= n; index--) {
|
|
1169
|
-
this.div(clone);
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
return this;
|
|
1174
|
-
});
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
/**
|
|
1178
|
-
* 开方
|
|
1179
|
-
*/
|
|
1180
|
-
sqrt() {
|
|
1181
|
-
return this.runMutation(() => {
|
|
1182
|
-
if (this.LE(Zero_Decimal)) {
|
|
1183
|
-
return this.set(1, Number.NaN, Number.NaN);
|
|
1184
|
-
}
|
|
1185
|
-
const decimal = 5 * Scale_L;
|
|
1186
|
-
|
|
1187
|
-
const x0 = TempA2.copy(this).div(TempA1.copy(Decimal.TWO));
|
|
1188
|
-
const x1 = TempA3.copy(this).div(TempA1.copy(Decimal.TWO).mul(x0)).add(TempA1.set(1, 0, decimal).mul(x0));
|
|
1189
|
-
|
|
1190
|
-
while (TempA1.copy(x1).sub(x0).abs().GT(Threshold_Decimal)) {
|
|
1191
|
-
x0.copy(x1);
|
|
1192
|
-
x1.copy(this).div(TempA1.copy(Decimal.TWO).mul(x0)).add(TempA1.set(1, 0, decimal).mul(x0));
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
this.sign = x1.sign;
|
|
1196
|
-
this.v1 = x1.v1;
|
|
1197
|
-
this.v2 = x1.v2;
|
|
1198
|
-
return this;
|
|
1199
|
-
});
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
/**
|
|
1203
|
-
* 小于
|
|
1204
|
-
* @param other
|
|
1205
|
-
*/
|
|
1206
|
-
LT(other: Decimal): boolean {
|
|
1207
|
-
return Decimal.compareSigned(this, other) < 0;
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
/**
|
|
1211
|
-
* 小于
|
|
1212
|
-
* @param other
|
|
1213
|
-
*/
|
|
1214
|
-
['<'](other: Decimal): boolean {
|
|
1215
|
-
return Decimal.compareSigned(this, other) < 0;
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
/**
|
|
1219
|
-
* 小于
|
|
1220
|
-
* @param other
|
|
1221
|
-
*/
|
|
1222
|
-
LTInt(other: IntNumber): boolean {
|
|
1223
|
-
return this.LT(Temp.setInt(other));
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
/**
|
|
1227
|
-
* 小于
|
|
1228
|
-
* @param other
|
|
1229
|
-
*/
|
|
1230
|
-
LTFloat(other: string): boolean {
|
|
1231
|
-
return this.LT(Temp.setFloat(other));
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
/**
|
|
1235
|
-
* 小于等于
|
|
1236
|
-
* @param other
|
|
1237
|
-
*/
|
|
1238
|
-
LE(other: Decimal): boolean {
|
|
1239
|
-
return Decimal.compareSigned(this, other) <= 0;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
/**
|
|
1243
|
-
* 小于等于
|
|
1244
|
-
* @param other
|
|
1245
|
-
*/
|
|
1246
|
-
['<='](other: Decimal): boolean {
|
|
1247
|
-
return Decimal.compareSigned(this, other) <= 0;
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
/**
|
|
1251
|
-
* 小于等于
|
|
1252
|
-
* @param other
|
|
1253
|
-
*/
|
|
1254
|
-
LEInt(other: IntNumber): boolean {
|
|
1255
|
-
return this.LE(Temp.setInt(other));
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
/**
|
|
1259
|
-
* 小于等于
|
|
1260
|
-
* @param other
|
|
1261
|
-
*/
|
|
1262
|
-
LEFloat(other: string): boolean {
|
|
1263
|
-
return this.LE(Temp.setFloat(other));
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
/**
|
|
1267
|
-
* 等于
|
|
1268
|
-
* @param other
|
|
1269
|
-
*/
|
|
1270
|
-
EQ(other: Decimal): boolean {
|
|
1271
|
-
return this.sign === other.sign && this.v1 === other.v1 && this.v2 === other.v2;
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
/**
|
|
1275
|
-
* 等于
|
|
1276
|
-
* @param other
|
|
1277
|
-
*/
|
|
1278
|
-
['=='](other: Decimal): boolean {
|
|
1279
|
-
return this.EQ(other);
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1282
|
-
/**
|
|
1283
|
-
* 等于
|
|
1284
|
-
* @param other
|
|
1285
|
-
*/
|
|
1286
|
-
EQInt(other: IntNumber): boolean {
|
|
1287
|
-
return this.EQ(Temp.setInt(other));
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
/**
|
|
1291
|
-
* 等于
|
|
1292
|
-
* @param other
|
|
1293
|
-
*/
|
|
1294
|
-
EQFloat(other: string): boolean {
|
|
1295
|
-
return this.EQ(Temp.setFloat(other));
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
/**
|
|
1299
|
-
* 不等于
|
|
1300
|
-
* @param other
|
|
1301
|
-
*/
|
|
1302
|
-
NE(other: Decimal): boolean {
|
|
1303
|
-
return !this.EQ(other);
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
/**
|
|
1307
|
-
* 不等于
|
|
1308
|
-
* @param other
|
|
1309
|
-
*/
|
|
1310
|
-
['!='](other: Decimal): boolean {
|
|
1311
|
-
return !this.EQ(other);
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
|
-
/**
|
|
1315
|
-
* 不等于
|
|
1316
|
-
* @param other
|
|
1317
|
-
*/
|
|
1318
|
-
NEInt(other: IntNumber): boolean {
|
|
1319
|
-
return this.NE(Temp.setInt(other));
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
/**
|
|
1323
|
-
* 不等于
|
|
1324
|
-
* @param other
|
|
1325
|
-
*/
|
|
1326
|
-
NEFloat(other: string): boolean {
|
|
1327
|
-
return this.NE(Temp.setFloat(other));
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
/**
|
|
1331
|
-
* 大于
|
|
1332
|
-
* @param other
|
|
1333
|
-
*/
|
|
1334
|
-
GT(other: Decimal): boolean {
|
|
1335
|
-
return Decimal.compareSigned(this, other) > 0;
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
/**
|
|
1339
|
-
* 大于
|
|
1340
|
-
* @param other
|
|
1341
|
-
*/
|
|
1342
|
-
['>'](other: Decimal): boolean {
|
|
1343
|
-
return Decimal.compareSigned(this, other) > 0;
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
/**
|
|
1347
|
-
* 大于
|
|
1348
|
-
* @param other
|
|
1349
|
-
*/
|
|
1350
|
-
GTInt(other: IntNumber): boolean {
|
|
1351
|
-
return this.GT(Temp.setInt(other));
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
|
-
/**
|
|
1355
|
-
* 大于
|
|
1356
|
-
* @param other
|
|
1357
|
-
*/
|
|
1358
|
-
GTFloat(other: string): boolean {
|
|
1359
|
-
return this.GT(Temp.setFloat(other));
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
/**
|
|
1363
|
-
* 大于等于
|
|
1364
|
-
* @param other
|
|
1365
|
-
*/
|
|
1366
|
-
GE(other: Decimal): boolean {
|
|
1367
|
-
return Decimal.compareSigned(this, other) >= 0;
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
/**
|
|
1371
|
-
* 大于等于
|
|
1372
|
-
* @param other
|
|
1373
|
-
*/
|
|
1374
|
-
['>='](other: Decimal): boolean {
|
|
1375
|
-
return Decimal.compareSigned(this, other) >= 0;
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
|
-
/**
|
|
1379
|
-
* 大于等于
|
|
1380
|
-
* @param other
|
|
1381
|
-
*/
|
|
1382
|
-
GEInt(other: IntNumber): boolean {
|
|
1383
|
-
return this.GE(Temp.setInt(other));
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
/**
|
|
1387
|
-
* 大于等于
|
|
1388
|
-
* @param other
|
|
1389
|
-
*/
|
|
1390
|
-
GEFloat(other: string): boolean {
|
|
1391
|
-
return this.GE(Temp.setFloat(other));
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
// 参数类型转换
|
|
1396
|
-
const Temp = new Decimal();
|
|
1397
|
-
|
|
1398
|
-
// 加减乘除
|
|
1399
|
-
const Temp1 = new Decimal();
|
|
1400
|
-
const Temp2 = new Decimal();
|
|
1401
|
-
|
|
1402
|
-
// 开方平方
|
|
1403
|
-
const TempA1 = new Decimal();
|
|
1404
|
-
const TempA2 = new Decimal();
|
|
1405
|
-
const TempA3 = new Decimal();
|
|
1406
|
-
|
|
1407
|
-
// 三角函数
|
|
1408
|
-
const TempB1 = new Decimal();
|
|
1409
|
-
const TempB2 = new Decimal();
|
|
1410
|
-
const TempB3 = new Decimal();
|
|
1411
|
-
const TempC1 = new Decimal();
|
|
1412
|
-
const TempC2 = new Decimal();
|
|
1413
|
-
const TempC3 = new Decimal();
|
|
1414
|
-
const TempD1 = new Decimal();
|
|
1415
|
-
|
|
1416
|
-
// 阶乘
|
|
1417
|
-
// const Factorial_Decimals: Decimal[] = [];
|
|
1418
|
-
|
|
1419
|
-
// 常量
|
|
1420
|
-
const Threshold_Decimal = Decimal.create(1, 0, 1);
|
|
1421
|
-
const Zero_Decimal = Decimal.createInt(0);
|
|
1422
|
-
const One_Decimal = Decimal.createInt(1);
|
|
1423
|
-
const Two_Decimal = Decimal.createInt(2);
|
|
1424
|
-
const Minus_Decimal = Decimal.createInt(-1);
|
|
1425
|
-
const PI_Decimal = Decimal.createFloat('3.141592653589793'); // PI
|
|
1426
|
-
const PI_HALF_Decimal = Decimal.createFloat('1.5707963267948966'); // PI / 2
|
|
1427
|
-
const Deg_Rad_Decimal = Decimal.createFloat('0.017453292519943'); // PI / 180
|
|
1428
|
-
const Rad_Deg_Decimal = Decimal.createFloat('57.29577951308232'); // 180 / PI
|