@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 CHANGED
@@ -1,8 +1,15 @@
1
1
  {
2
2
  "name": "@tktb-tess/util-fns",
3
- "version": "0.2.0",
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
- value = 1 / (value - Number(a_0));
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
- value = 1 / (value - Number(a_n1));
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
- this.#numerator /= gcd;
62
- this.#denominator /= gcd;
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
- return `${this.#numerator}/${this.#denominator}`;
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('binary').slice(0, length);
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 << ((32 - rot) & 31))) >>> 0;
225
+ return ((value >>> (rot & 31)) | (value << (-rot & 31))) >>> 0;
224
226
  };
225
227
 
226
228
  /**