-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
math.ts
79 lines (55 loc) · 2.25 KB
/
math.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
export function sum(...data: number[]) {
return data.reduce((sum, item) => sum + item, 0);
}
export function averageOf(...data: number[]) {
return sum(...data) / data.length;
}
export function varianceOf(data: number[], sample = false) {
const average = averageOf(...data);
const summary = sum(...data.map(item => (item - average) ** 2));
return summary / (data.length - (sample ? 1 : 0));
}
export function standardDeviationOf(data: number[], sample = false) {
return Math.sqrt(varianceOf(data, sample));
}
export function hypotenuseOf(...data: number[]) {
return Math.sqrt(sum(...data.map(item => item ** 2)));
}
export function carryFloat(raw: number, length: number) {
const text = raw.toFixed(length + 2);
const offset = text.indexOf('.') + length + 1;
const cut = (text: string) => text.slice(0, offset - (length ? 0 : 1));
if (!+text.slice(offset)) return cut(text);
const result = cut((+cut(text) + 10 ** -length).toFixed(length));
return result.includes('.') ? result.padEnd(offset, '0') : result;
}
export function fixFloat(raw: number, length = 2) {
const text = raw.toFixed(length + 2);
const floatOffset = text.indexOf('.');
if (floatOffset < 0) return length ? `${text}.${'0'.repeat(length)}` : text;
const offset = floatOffset + length + 1;
const before = +text[offset - 1],
anchor = +text[offset],
after = +text[offset + 1];
const carry = anchor > 5 || (anchor === 5 && (!!after || !!(before % 2)));
if (carry) return carryFloat(raw, length);
const result = text.slice(0, offset - (length ? 0 : 1));
return result.includes('.') ? result.padEnd(offset, '0') : result;
}
export abstract class Scalar {
abstract units: { base: number; name: string }[];
constructor(public value: number) {}
valueOf() {
return this.value;
}
toShortString(fractionDigits = 2) {
const { units, value } = this;
const { base, name } =
[...units].reverse().find(({ base }) => Math.abs(value) >= base) ||
units[0];
return `${(value / base).toFixed(fractionDigits)} ${name}`;
}
static distanceOf<T extends Scalar>(a: number, b: number) {
return Reflect.construct(this, [a - b]) as T;
}
}