@tktb-tess/util-fns 0.2.0 → 0.2.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/package.json +8 -4
- package/src/fraction.ts +50 -8
- package/src/math.ts +4 -2
package/package.json
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tktb-tess/util-fns",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "utility functions for personal use",
|
|
4
5
|
"main": "dist/main.js",
|
|
5
6
|
"type": "module",
|
|
7
|
+
"author": "Tessyrrhaqt",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/tktb-tess/util-fns"
|
|
12
|
+
},
|
|
6
13
|
"publishConfig": {
|
|
7
14
|
"access": "public"
|
|
8
15
|
},
|
|
@@ -10,9 +17,6 @@
|
|
|
10
17
|
"build": "rm -r -f dist && rollup -c",
|
|
11
18
|
"test": "npx tsx test/main.test.ts"
|
|
12
19
|
},
|
|
13
|
-
"author": "Tessyrrhaqt",
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"description": "utility functions for personal use",
|
|
16
20
|
"devDependencies": {
|
|
17
21
|
"@rollup/plugin-commonjs": "^28.0.6",
|
|
18
22
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
package/src/fraction.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { exEuclidean } from './math';
|
|
2
2
|
const __fraction_brand = Symbol();
|
|
3
3
|
|
|
4
|
+
export type FractionData = {
|
|
5
|
+
type: 'Fraction';
|
|
6
|
+
numerator: string;
|
|
7
|
+
denominator: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
4
10
|
export default class Fraction {
|
|
5
11
|
#numerator: bigint;
|
|
6
12
|
#denominator: bigint;
|
|
@@ -36,7 +42,11 @@ export default class Fraction {
|
|
|
36
42
|
if (isNegative) value *= -1;
|
|
37
43
|
|
|
38
44
|
const a_0 = BigInt(Math.floor(value));
|
|
39
|
-
|
|
45
|
+
const fracPart = value - Number(a_0);
|
|
46
|
+
if (fracPart === 0) {
|
|
47
|
+
return new Fraction(isNegative ? -a_0 : a_0, 1n);
|
|
48
|
+
}
|
|
49
|
+
value = 1 / fracPart;
|
|
40
50
|
|
|
41
51
|
// 漸化式 参考: https://tsujimotter.hatenablog.com/entry/continued-fraction
|
|
42
52
|
// p_0 = 1, p_1 = a_0, p_{n+2} = a_{n+1} * p_{n+1} + p_n
|
|
@@ -46,9 +56,16 @@ export default class Fraction {
|
|
|
46
56
|
|
|
47
57
|
while (`${q_n1}`.length < denominatorDigits + 1) {
|
|
48
58
|
const a_n1 = BigInt(Math.floor(value));
|
|
49
|
-
|
|
59
|
+
const fracPart = value - Number(a_n1);
|
|
60
|
+
|
|
50
61
|
[p_n, p_n1] = [p_n1, a_n1 * p_n1 + p_n];
|
|
51
62
|
[q_n, q_n1] = [q_n1, a_n1 * q_n1 + q_n];
|
|
63
|
+
|
|
64
|
+
if (fracPart === 0) {
|
|
65
|
+
return new Fraction(isNegative ? -p_n1 : p_n1, q_n1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
value = 1 / fracPart;
|
|
52
69
|
}
|
|
53
70
|
return new Fraction(isNegative ? -p_n : p_n, q_n);
|
|
54
71
|
}
|
|
@@ -58,8 +75,10 @@ export default class Fraction {
|
|
|
58
75
|
*/
|
|
59
76
|
#reduction() {
|
|
60
77
|
const { gcd } = exEuclidean(this.#numerator, this.#denominator);
|
|
61
|
-
|
|
62
|
-
|
|
78
|
+
if (gcd !== 0n) {
|
|
79
|
+
this.#numerator /= gcd;
|
|
80
|
+
this.#denominator /= gcd;
|
|
81
|
+
}
|
|
63
82
|
}
|
|
64
83
|
|
|
65
84
|
/**
|
|
@@ -135,18 +154,41 @@ export default class Fraction {
|
|
|
135
154
|
* @returns
|
|
136
155
|
*/
|
|
137
156
|
toString() {
|
|
138
|
-
|
|
157
|
+
if (this.#numerator === 0n && this.#denominator === 0n) {
|
|
158
|
+
return `NaN`;
|
|
159
|
+
} else if (this.#numerator === 0n) {
|
|
160
|
+
return `0`;
|
|
161
|
+
} else if (this.#denominator === 0n) {
|
|
162
|
+
return this.#numerator < 0n ? `-Infinity` : `Infinity`;
|
|
163
|
+
} else if (this.#denominator === 1n) {
|
|
164
|
+
return `${this.#numerator}`;
|
|
165
|
+
} else {
|
|
166
|
+
return `${this.#numerator}/${this.#denominator}`;
|
|
167
|
+
}
|
|
139
168
|
}
|
|
140
169
|
|
|
141
170
|
valueOf() {
|
|
142
171
|
return this.toDecimal();
|
|
143
172
|
}
|
|
144
173
|
|
|
145
|
-
toJSON() {
|
|
174
|
+
toJSON(): FractionData {
|
|
146
175
|
return {
|
|
147
176
|
type: 'Fraction',
|
|
148
|
-
numerator: this.#numerator.toString(),
|
|
149
|
-
denominator: this.#denominator.toString(),
|
|
177
|
+
numerator: '0x' + this.#numerator.toString(16),
|
|
178
|
+
denominator: '0x' + this.#denominator.toString(16),
|
|
150
179
|
};
|
|
151
180
|
}
|
|
181
|
+
|
|
182
|
+
static parse(text: string) {
|
|
183
|
+
const parsed = JSON.parse(text);
|
|
184
|
+
const { type, numerator, denominator } = parsed;
|
|
185
|
+
if (type !== 'Fraction') throw Error('cannot parse');
|
|
186
|
+
if (typeof numerator === 'string' && typeof denominator === 'string') {
|
|
187
|
+
const num = BigInt(numerator);
|
|
188
|
+
const denom = BigInt(denominator);
|
|
189
|
+
return new Fraction(num, denom);
|
|
190
|
+
} else {
|
|
191
|
+
throw Error('cannot parse');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
152
194
|
}
|
package/src/math.ts
CHANGED
|
@@ -40,7 +40,9 @@ export const getRandBIByBitLength = (length: number, fixed = false) => {
|
|
|
40
40
|
|
|
41
41
|
const byteLen = Math.ceil(length / 8);
|
|
42
42
|
const buf = crypto.getRandomValues(Buffer.alloc(byteLen));
|
|
43
|
-
let result = buf.toString(
|
|
43
|
+
let result = Array.from(buf, (n) => n.toString(2).padStart(8, '0'))
|
|
44
|
+
.join('')
|
|
45
|
+
.slice(0, length);
|
|
44
46
|
|
|
45
47
|
if (fixed) result = result.replace(/^./, '1');
|
|
46
48
|
// console.log(result);
|
|
@@ -220,7 +222,7 @@ export const rot32BI = (value: bigint, rot: bigint) => {
|
|
|
220
222
|
* @returns
|
|
221
223
|
*/
|
|
222
224
|
export const rot32 = (value: number, rot: number) => {
|
|
223
|
-
return ((value >>> (rot & 31)) | (value << (
|
|
225
|
+
return ((value >>> (rot & 31)) | (value << (-rot & 31))) >>> 0;
|
|
224
226
|
};
|
|
225
227
|
|
|
226
228
|
/**
|