smart-unit 1.0.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/LICENSE +9 -0
- package/README.md +229 -0
- package/README.zh-CN.md +229 -0
- package/dist/browser.umd.js +14 -0
- package/dist/index.d.ts +110 -0
- package/dist/index.esm.js +228 -0
- package/dist/index.js +235 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) <2025> <flycran>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
|
package/README.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# smart-unit
|
|
2
|
+
|
|
3
|
+
> Elegant unit conversion utility for JavaScript & TypeScript
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/smart-unit)
|
|
6
|
+
[](https://www.npmjs.com/package/smart-unit)
|
|
7
|
+
[](https://bundlephobia.com/package/smart-unit)
|
|
8
|
+
[](./LICENSE)
|
|
9
|
+
|
|
10
|
+
English | [中文](./README.zh-CN.md)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
**smart-unit** is a lightweight utility for automatic unit conversion with intelligent formatting.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- 🎯 **Smart Formatting** — Automatically selects the optimal unit for display
|
|
19
|
+
- 🔢 **Bidirectional** — Convert to units (`format`) and from units (`parse`)
|
|
20
|
+
- ⚡ **High Performance** — Minimal overhead, works in Node.js and browsers
|
|
21
|
+
- 🧮 **High Precision** — Optional `decimal.js` integration for arbitrary precision
|
|
22
|
+
- 📦 **TypeScript First** — Full type safety
|
|
23
|
+
- 🪶 **Lightweight** — Core functionality with minimal footprint
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install smart-unit
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Try It Online
|
|
32
|
+
|
|
33
|
+
[](https://codesandbox.io/s/github/flycran/smart-unit/tree/master/examples/basic)
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
### File Size Formatting
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import SmartUnit from 'smart-unit';
|
|
41
|
+
|
|
42
|
+
const fileSize = new SmartUnit(['B', 'KB', 'MB', 'GB', 'TB'], {
|
|
43
|
+
baseDigit: 1024,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
fileSize.format(1024 * 1024 * 100); // => "100MB"
|
|
47
|
+
fileSize.format(1536); // => "1.5KB"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Length Units with Variable Ratios
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const length = new SmartUnit(['mm', 10, 'cm', 100, 'm', 1000, 'km']);
|
|
54
|
+
|
|
55
|
+
length.format(1500); // => "1.5m"
|
|
56
|
+
length.format(1500000); // => "1.5km"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### High-Precision & BigInt Support
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const bigLength = new SmartUnit(
|
|
63
|
+
['mm', 10, 'cm', 100, 'm', 1000, 'km', 1000, 'Mm', 1000, 'Gm', 1000, 'Tm'],
|
|
64
|
+
{ useDecimal: true }
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// Works with BigInt and numbers beyond JS safe integer range
|
|
68
|
+
bigLength.format(10n ** 18n); // => "1000Tm"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Parse Unit Strings
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const time = new SmartUnit(['ms', 1000, 's', 60, 'm', 60, 'h']);
|
|
75
|
+
|
|
76
|
+
time.parse('90s'); // => 90000 (ms)
|
|
77
|
+
time.parse('2.5h'); // => 9000000 (ms)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## API
|
|
81
|
+
|
|
82
|
+
### `new SmartUnit(units, options?)`
|
|
83
|
+
|
|
84
|
+
Creates a unit converter instance.
|
|
85
|
+
|
|
86
|
+
#### Parameters
|
|
87
|
+
|
|
88
|
+
- **units** `(string | number)[]` — Array of unit names and conversion ratios
|
|
89
|
+
- Even indices: unit names (e.g., `'B'`, `'KB'`)
|
|
90
|
+
- Odd indices: conversion ratios to next unit (e.g., `1024`)
|
|
91
|
+
- **options** `SmartUnitOptions` — Configuration object
|
|
92
|
+
- `baseDigit?: number` — Auto-generate ratios (e.g., `1024` for all steps)
|
|
93
|
+
- `threshold?: number` — Unit switch threshold (default: `1`)
|
|
94
|
+
- `fractionDigits?: FractionDigits` — Decimal places for formatting
|
|
95
|
+
- `useDecimal?: boolean` — Enable high-precision mode
|
|
96
|
+
- `decimalOptions?: Decimal.Config` — Custom decimal.js configuration
|
|
97
|
+
|
|
98
|
+
#### Methods
|
|
99
|
+
|
|
100
|
+
##### `.format(num, decimal?)`
|
|
101
|
+
|
|
102
|
+
Formats a number to the optimal unit string.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const size = new SmartUnit(['B', 'KB', 1024, 'MB'], { fractionDigits: 2 });
|
|
106
|
+
|
|
107
|
+
size.format(1536); // => "1.5KB"
|
|
108
|
+
size.format(1536, 0); // => "2KB"
|
|
109
|
+
size.format(1536, '1-3'); // => "1.5KB" (min 1, max 3 decimals)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
##### `.parse(str)`
|
|
113
|
+
|
|
114
|
+
Parses a unit string back to base unit value.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const size = new SmartUnit(['B', 'KB', 1024, 'MB']);
|
|
118
|
+
|
|
119
|
+
size.parse('1.5KB'); // => 1536
|
|
120
|
+
size.parse('2MB'); // => 2097152
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
##### `.getUnit(num)`
|
|
124
|
+
|
|
125
|
+
Gets the optimal unit and converted value without formatting.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const size = new SmartUnit(['B', 'KB', 1024, 'MB']);
|
|
129
|
+
|
|
130
|
+
size.getUnit(1536);
|
|
131
|
+
// => { num: 1.5, unit: 'KB' }
|
|
132
|
+
|
|
133
|
+
// With high precision
|
|
134
|
+
const precise = new SmartUnit(['B', 'KB', 1024], { useDecimal: true });
|
|
135
|
+
precise.getUnit(1536);
|
|
136
|
+
// => { num: 1.5, unit: 'KB', decimal: Decimal }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
##### `.toBase(num, unit)`
|
|
140
|
+
|
|
141
|
+
Converts a value from specified unit to base unit.
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const length = new SmartUnit(['mm', 10, 'cm', 100, 'm']);
|
|
145
|
+
|
|
146
|
+
length.toBase(1.5, 'm'); // => 1500 (mm)
|
|
147
|
+
length.toBase(100, 'cm'); // => 1000 (mm)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
##### `.splitUnit(str)`
|
|
151
|
+
|
|
152
|
+
Extracts numeric value and unit from a formatted string.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
const size = new SmartUnit(['B', 'KB', 1024, 'MB']);
|
|
156
|
+
|
|
157
|
+
size.splitUnit('1.5KB'); // => { num: 1.5, unit: 'KB' }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
##### `.fromUnitFormat(num, unit, decimal?)`
|
|
161
|
+
|
|
162
|
+
Converts from one unit to the optimal unit and formats.
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const length = new SmartUnit(['mm', 10, 'cm', 100, 'm', 1000, 'km']);
|
|
166
|
+
|
|
167
|
+
length.fromUnitFormat(1500, 'm'); // => "1.5km"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Use Cases
|
|
171
|
+
|
|
172
|
+
### Data Transfer Rate
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const bitrate = new SmartUnit(['bps', 'Kbps', 'Mbps', 'Gbps'], {
|
|
176
|
+
baseDigit: 1000,
|
|
177
|
+
fractionDigits: 1,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
bitrate.format(1500000); // => "1.5Mbps"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Frequency
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const freq = new SmartUnit(['Hz', 'kHz', 'MHz', 'GHz'], {
|
|
187
|
+
baseDigit: 1000,
|
|
188
|
+
fractionDigits: 2,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
freq.format(2400000000); // => "2.4GHz"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Financial Amounts (High Precision)
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
const currency = new SmartUnit(['', 'K', 'M', 'B', 'T'], {
|
|
198
|
+
baseDigit: 1000,
|
|
199
|
+
useDecimal: true,
|
|
200
|
+
fractionDigits: 2,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
currency.format('12345678901234567890'); // => "12345678.9T"
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## TypeScript
|
|
207
|
+
|
|
208
|
+
smart-unit is written in TypeScript and provides full type safety.
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import SmartUnit from 'smart-unit';
|
|
212
|
+
import type { Decimal } from 'decimal.js';
|
|
213
|
+
|
|
214
|
+
// Regular mode - returns number
|
|
215
|
+
const regular = new SmartUnit(['B', 'KB', 1024]);
|
|
216
|
+
const num: number = regular.parse('1KB');
|
|
217
|
+
|
|
218
|
+
// High-precision mode - returns Decimal
|
|
219
|
+
const precise = new SmartUnit(['B', 'KB', 1024], { useDecimal: true });
|
|
220
|
+
const dec: Decimal = precise.parse('1KB');
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Contributing
|
|
224
|
+
|
|
225
|
+
Contributions are welcome! Please feel free to submit issues or pull requests.
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
MIT © [flycran](https://github.com/flycran)
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# smart-unit
|
|
2
|
+
|
|
3
|
+
> 优雅的 JavaScript & TypeScript 单位转换工具
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/smart-unit)
|
|
6
|
+
[](https://www.npmjs.com/package/smart-unit)
|
|
7
|
+
[](https://bundlephobia.com/package/smart-unit)
|
|
8
|
+
[](./LICENSE)
|
|
9
|
+
|
|
10
|
+
[English](./README.md) | 中文
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
**smart-unit** 是一个轻量级的自动单位转换工具,支持智能格式化输出。
|
|
15
|
+
|
|
16
|
+
## 特性
|
|
17
|
+
|
|
18
|
+
- 🎯 **智能格式化** — 自动选择最优单位进行展示
|
|
19
|
+
- 🔢 **双向转换** — 支持单位格式化(`format`)和反向解析(`parse`)
|
|
20
|
+
- ⚡ **高性能** — 极小开销,支持 Node.js 和浏览器
|
|
21
|
+
- 🧮 **高精度** — 可选 `decimal.js` 集成,支持任意精度计算
|
|
22
|
+
- 📦 **TypeScript 优先** — 完整的类型安全
|
|
23
|
+
- 🪶 **轻量级** — 核心功能,体积小巧
|
|
24
|
+
|
|
25
|
+
## 安装
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install smart-unit
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 在线体验
|
|
32
|
+
|
|
33
|
+
[](https://codesandbox.io/s/github/flycran/smart-unit/tree/master/examples/basic)
|
|
34
|
+
|
|
35
|
+
## 快速开始
|
|
36
|
+
|
|
37
|
+
### 文件大小格式化
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import SmartUnit from 'smart-unit';
|
|
41
|
+
|
|
42
|
+
const fileSize = new SmartUnit(['B', 'KB', 'MB', 'GB', 'TB'], {
|
|
43
|
+
baseDigit: 1024,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
fileSize.format(1024 * 1024 * 100); // => "100MB"
|
|
47
|
+
fileSize.format(1536); // => "1.5KB"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 可变进制长度单位
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const length = new SmartUnit(['mm', 10, 'cm', 100, 'm', 1000, 'km']);
|
|
54
|
+
|
|
55
|
+
length.format(1500); // => "1.5m"
|
|
56
|
+
length.format(1500000); // => "1.5km"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 高精度与 BigInt 支持
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const bigLength = new SmartUnit(
|
|
63
|
+
['mm', 10, 'cm', 100, 'm', 1000, 'km', 1000, 'Mm', 1000, 'Gm', 1000, 'Tm'],
|
|
64
|
+
{ useDecimal: true }
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// 支持 BigInt 和超出 JS 安全整数范围的数值
|
|
68
|
+
bigLength.format(10n ** 18n); // => "1000Tm"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 解析单位字符串
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const time = new SmartUnit(['ms', 1000, 's', 60, 'm', 60, 'h']);
|
|
75
|
+
|
|
76
|
+
time.parse('90s'); // => 90000 (ms)
|
|
77
|
+
time.parse('2.5h'); // => 9000000 (ms)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## API
|
|
81
|
+
|
|
82
|
+
### `new SmartUnit(units, options?)`
|
|
83
|
+
|
|
84
|
+
创建单位转换器实例。
|
|
85
|
+
|
|
86
|
+
#### 参数
|
|
87
|
+
|
|
88
|
+
- **units** `(string | number)[]` — 单位名称和转换比例数组
|
|
89
|
+
- 偶数索引:单位名称(如 `'B'`、`'KB'`)
|
|
90
|
+
- 奇数索引:到下一单位的转换比例(如 `1024`)
|
|
91
|
+
- **options** `SmartUnitOptions` — 配置对象
|
|
92
|
+
- `baseDigit?: number` — 自动生成比例(如 `1024` 表示所有步骤)
|
|
93
|
+
- `threshold?: number` — 单位切换阈值(默认:`1`)
|
|
94
|
+
- `fractionDigits?: FractionDigits` — 格式化小数位数
|
|
95
|
+
- `useDecimal?: boolean` — 启用高精度模式
|
|
96
|
+
- `decimalOptions?: Decimal.Config` — 自定义 decimal.js 配置
|
|
97
|
+
|
|
98
|
+
#### 方法
|
|
99
|
+
|
|
100
|
+
##### `.format(num, decimal?)`
|
|
101
|
+
|
|
102
|
+
将数字格式化为最优单位字符串。
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const size = new SmartUnit(['B', 'KB', 1024, 'MB'], { fractionDigits: 2 });
|
|
106
|
+
|
|
107
|
+
size.format(1536); // => "1.5KB"
|
|
108
|
+
size.format(1536, 0); // => "2KB"
|
|
109
|
+
size.format(1536, '1-3'); // => "1.5KB"(最少1位,最多3位小数)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
##### `.parse(str)`
|
|
113
|
+
|
|
114
|
+
将单位字符串解析回基本单位值。
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const size = new SmartUnit(['B', 'KB', 1024, 'MB']);
|
|
118
|
+
|
|
119
|
+
size.parse('1.5KB'); // => 1536
|
|
120
|
+
size.parse('2MB'); // => 2097152
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
##### `.getUnit(num)`
|
|
124
|
+
|
|
125
|
+
获取最优单位和转换后的值(不进行格式化)。
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const size = new SmartUnit(['B', 'KB', 1024, 'MB']);
|
|
129
|
+
|
|
130
|
+
size.getUnit(1536);
|
|
131
|
+
// => { num: 1.5, unit: 'KB' }
|
|
132
|
+
|
|
133
|
+
// 高精度模式
|
|
134
|
+
const precise = new SmartUnit(['B', 'KB', 1024], { useDecimal: true });
|
|
135
|
+
precise.getUnit(1536);
|
|
136
|
+
// => { num: 1.5, unit: 'KB', decimal: Decimal }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
##### `.toBase(num, unit)`
|
|
140
|
+
|
|
141
|
+
将指定单位的值转换为基本单位。
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const length = new SmartUnit(['mm', 10, 'cm', 100, 'm']);
|
|
145
|
+
|
|
146
|
+
length.toBase(1.5, 'm'); // => 1500 (mm)
|
|
147
|
+
length.toBase(100, 'cm'); // => 1000 (mm)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
##### `.splitUnit(str)`
|
|
151
|
+
|
|
152
|
+
从格式化字符串中提取数值和单位。
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
const size = new SmartUnit(['B', 'KB', 1024, 'MB']);
|
|
156
|
+
|
|
157
|
+
size.splitUnit('1.5KB'); // => { num: 1.5, unit: 'KB' }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
##### `.fromUnitFormat(num, unit, decimal?)`
|
|
161
|
+
|
|
162
|
+
从一种单位转换到最优单位并格式化。
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const length = new SmartUnit(['mm', 10, 'cm', 100, 'm', 1000, 'km']);
|
|
166
|
+
|
|
167
|
+
length.fromUnitFormat(1500, 'm'); // => "1.5km"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 使用场景
|
|
171
|
+
|
|
172
|
+
### 数据传输速率
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const bitrate = new SmartUnit(['bps', 'Kbps', 'Mbps', 'Gbps'], {
|
|
176
|
+
baseDigit: 1000,
|
|
177
|
+
fractionDigits: 1,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
bitrate.format(1500000); // => "1.5Mbps"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 频率
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const freq = new SmartUnit(['Hz', 'kHz', 'MHz', 'GHz'], {
|
|
187
|
+
baseDigit: 1000,
|
|
188
|
+
fractionDigits: 2,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
freq.format(2400000000); // => "2.4GHz"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 金融金额(高精度)
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
const currency = new SmartUnit(['', 'K', 'M', 'B', 'T'], {
|
|
198
|
+
baseDigit: 1000,
|
|
199
|
+
useDecimal: true,
|
|
200
|
+
fractionDigits: 2,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
currency.format('12345678901234567890'); // => "12345678.9T"
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## TypeScript
|
|
207
|
+
|
|
208
|
+
smart-unit 使用 TypeScript 编写,提供完整的类型安全。
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import SmartUnit from 'smart-unit';
|
|
212
|
+
import type { Decimal } from 'decimal.js';
|
|
213
|
+
|
|
214
|
+
// 普通模式 - 返回 number
|
|
215
|
+
const regular = new SmartUnit(['B', 'KB', 1024]);
|
|
216
|
+
const num: number = regular.parse('1KB');
|
|
217
|
+
|
|
218
|
+
// 高精度模式 - 返回 Decimal
|
|
219
|
+
const precise = new SmartUnit(['B', 'KB', 1024], { useDecimal: true });
|
|
220
|
+
const dec: Decimal = precise.parse('1KB');
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## 贡献
|
|
224
|
+
|
|
225
|
+
欢迎贡献!请随时提交 issue 或 pull request。
|
|
226
|
+
|
|
227
|
+
## 许可证
|
|
228
|
+
|
|
229
|
+
MIT © [flycran](https://github.com/flycran)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).SmartUnit={})}(this,(function(n){"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* decimal.js v10.5.0
|
|
4
|
+
* An arbitrary-precision Decimal type for JavaScript.
|
|
5
|
+
* https://github.com/MikeMcl/decimal.js
|
|
6
|
+
* Copyright (c) 2025 Michael Mclaughlin <M8ch88l@gmail.com>
|
|
7
|
+
* MIT Licence
|
|
8
|
+
*/var e,i,t=9e15,r=1e9,s="0123456789abcdef",o="2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058",u="3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789",c={precision:20,rounding:4,modulo:1,toExpNeg:-7,toExpPos:21,minE:-9e15,maxE:t,crypto:!1},f=!0,h="[DecimalError] ",a=h+"Invalid argument: ",l=h+"Precision limit exceeded",d=h+"crypto unavailable",g="[object Decimal]",p=Math.floor,m=Math.pow,w=/^0b([01]+(\.[01]*)?|\.[01]+)(p[+-]?\d+)?$/i,v=/^0x([0-9a-f]+(\.[0-9a-f]*)?|\.[0-9a-f]+)(p[+-]?\d+)?$/i,N=/^0o([0-7]+(\.[0-7]*)?|\.[0-7]+)(p[+-]?\d+)?$/i,b=/^(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,E=1e7,y=o.length-1,x=u.length-1,S={toStringTag:g};function M(n){var e,i,t,r=n.length-1,s="",o=n[0];if(r>0){for(s+=o,e=1;e<r;e++)(i=7-(t=n[e]+"").length)&&(s+=Z(i)),s+=t;(i=7-(t=(o=n[e])+"").length)&&(s+=Z(i))}else if(0===o)return"0";for(;o%10==0;)o/=10;return s+o}function O(n,e,i){if(n!==~~n||n<e||n>i)throw Error(a+n)}function q(n,e,i,t){var r,s,o,u;for(s=n[0];s>=10;s/=10)--e;return--e<0?(e+=7,r=0):(r=Math.ceil((e+1)/7),e%=7),s=m(10,7-e),u=n[r]%s|0,null==t?e<3?(0==e?u=u/100|0:1==e&&(u=u/10|0),o=i<4&&99999==u||i>3&&49999==u||5e4==u||0==u):o=(i<4&&u+1==s||i>3&&u+1==s/2)&&(n[r+1]/s/100|0)==m(10,e-2)-1||(u==s/2||0==u)&&!(n[r+1]/s/100|0):e<4?(0==e?u=u/1e3|0:1==e?u=u/100|0:2==e&&(u=u/10|0),o=(t||i<4)&&9999==u||!t&&i>3&&4999==u):o=((t||i<4)&&u+1==s||!t&&i>3&&u+1==s/2)&&(n[r+1]/s/1e3|0)==m(10,e-3)-1,o}function D(n,e,i){for(var t,r,o=[0],u=0,c=n.length;u<c;){for(r=o.length;r--;)o[r]*=e;for(o[0]+=s.indexOf(n.charAt(u++)),t=0;t<o.length;t++)o[t]>i-1&&(void 0===o[t+1]&&(o[t+1]=0),o[t+1]+=o[t]/i|0,o[t]%=i)}return o.reverse()}S.absoluteValue=S.abs=function(){var n=new this.constructor(this);return n.s<0&&(n.s=1),T(n)},S.ceil=function(){return T(new this.constructor(this),this.e+1,2)},S.clampedTo=S.clamp=function(n,e){var i=this,t=i.constructor;if(n=new t(n),e=new t(e),!n.s||!e.s)return new t(NaN);if(n.gt(e))throw Error(a+e);return i.cmp(n)<0?n:i.cmp(e)>0?e:new t(i)},S.comparedTo=S.cmp=function(n){var e,i,t,r,s=this,o=s.d,u=(n=new s.constructor(n)).d,c=s.s,f=n.s;if(!o||!u)return c&&f?c!==f?c:o===u?0:!o^c<0?1:-1:NaN;if(!o[0]||!u[0])return o[0]?c:u[0]?-f:0;if(c!==f)return c;if(s.e!==n.e)return s.e>n.e^c<0?1:-1;for(e=0,i=(t=o.length)<(r=u.length)?t:r;e<i;++e)if(o[e]!==u[e])return o[e]>u[e]^c<0?1:-1;return t===r?0:t>r^c<0?1:-1},S.cosine=S.cos=function(){var n,e,t=this,r=t.constructor;return t.d?t.d[0]?(n=r.precision,e=r.rounding,r.precision=n+Math.max(t.e,t.sd())+7,r.rounding=1,t=function(n,e){var i,t,r;if(e.isZero())return e;t=e.d.length,t<32?r=(1/W(4,i=Math.ceil(t/3))).toString():(i=16,r="2.3283064365386962890625e-10");n.precision+=i,e=V(n,1,e.times(r),new n(1));for(var s=i;s--;){var o=e.times(e);e=o.times(o).minus(o).times(8).plus(1)}return n.precision-=i,e}(r,G(r,t)),r.precision=n,r.rounding=e,T(2==i||3==i?t.neg():t,n,e,!0)):new r(1):new r(NaN)},S.cubeRoot=S.cbrt=function(){var n,e,i,t,r,s,o,u,c,h,a=this,l=a.constructor;if(!a.isFinite()||a.isZero())return new l(a);for(f=!1,(s=a.s*m(a.s*a,1/3))&&Math.abs(s)!=1/0?t=new l(s.toString()):(i=M(a.d),(s=((n=a.e)-i.length+1)%3)&&(i+=1==s||-2==s?"0":"00"),s=m(i,1/3),n=p((n+1)/3)-(n%3==(n<0?-1:2)),(t=new l(i=s==1/0?"5e"+n:(i=s.toExponential()).slice(0,i.indexOf("e")+1)+n)).s=a.s),o=(n=l.precision)+3;;)if(h=(c=(u=t).times(u).times(u)).plus(a),t=F(h.plus(a).times(u),h.plus(c),o+2,1),M(u.d).slice(0,o)===(i=M(t.d)).slice(0,o)){if("9999"!=(i=i.slice(o-3,o+1))&&(r||"4999"!=i)){+i&&(+i.slice(1)||"5"!=i.charAt(0))||(T(t,n+1,1),e=!t.times(t).times(t).eq(a));break}if(!r&&(T(u,n+1,0),u.times(u).times(u).eq(a))){t=u;break}o+=4,r=1}return f=!0,T(t,n,l.rounding,e)},S.decimalPlaces=S.dp=function(){var n,e=this.d,i=NaN;if(e){if(i=7*((n=e.length-1)-p(this.e/7)),n=e[n])for(;n%10==0;n/=10)i--;i<0&&(i=0)}return i},S.dividedBy=S.div=function(n){return F(this,new this.constructor(n))},S.dividedToIntegerBy=S.divToInt=function(n){var e=this.constructor;return T(F(this,new e(n),0,1,1),e.precision,e.rounding)},S.equals=S.eq=function(n){return 0===this.cmp(n)},S.floor=function(){return T(new this.constructor(this),this.e+1,3)},S.greaterThan=S.gt=function(n){return this.cmp(n)>0},S.greaterThanOrEqualTo=S.gte=function(n){var e=this.cmp(n);return 1==e||0===e},S.hyperbolicCosine=S.cosh=function(){var n,e,i,t,r,s=this,o=s.constructor,u=new o(1);if(!s.isFinite())return new o(s.s?1/0:NaN);if(s.isZero())return u;i=o.precision,t=o.rounding,o.precision=i+Math.max(s.e,s.sd())+4,o.rounding=1,(r=s.d.length)<32?e=(1/W(4,n=Math.ceil(r/3))).toString():(n=16,e="2.3283064365386962890625e-10"),s=V(o,1,s.times(e),new o(1),!0);for(var c,f=n,h=new o(8);f--;)c=s.times(s),s=u.minus(c.times(h.minus(c.times(h))));return T(s,o.precision=i,o.rounding=t,!0)},S.hyperbolicSine=S.sinh=function(){var n,e,i,t,r=this,s=r.constructor;if(!r.isFinite()||r.isZero())return new s(r);if(e=s.precision,i=s.rounding,s.precision=e+Math.max(r.e,r.sd())+4,s.rounding=1,(t=r.d.length)<3)r=V(s,2,r,r,!0);else{n=(n=1.4*Math.sqrt(t))>16?16:0|n,r=V(s,2,r=r.times(1/W(5,n)),r,!0);for(var o,u=new s(5),c=new s(16),f=new s(20);n--;)o=r.times(r),r=r.times(u.plus(o.times(c.times(o).plus(f))))}return s.precision=e,s.rounding=i,T(r,e,i,!0)},S.hyperbolicTangent=S.tanh=function(){var n,e,i=this,t=i.constructor;return i.isFinite()?i.isZero()?new t(i):(n=t.precision,e=t.rounding,t.precision=n+7,t.rounding=1,F(i.sinh(),i.cosh(),t.precision=n,t.rounding=e)):new t(i.s)},S.inverseCosine=S.acos=function(){var n=this,e=n.constructor,i=n.abs().cmp(1),t=e.precision,r=e.rounding;return-1!==i?0===i?n.isNeg()?P(e,t,r):new e(0):new e(NaN):n.isZero()?P(e,t+4,r).times(.5):(e.precision=t+6,e.rounding=1,n=new e(1).minus(n).div(n.plus(1)).sqrt().atan(),e.precision=t,e.rounding=r,n.times(2))},S.inverseHyperbolicCosine=S.acosh=function(){var n,e,i=this,t=i.constructor;return i.lte(1)?new t(i.eq(1)?0:NaN):i.isFinite()?(n=t.precision,e=t.rounding,t.precision=n+Math.max(Math.abs(i.e),i.sd())+4,t.rounding=1,f=!1,i=i.times(i).minus(1).sqrt().plus(i),f=!0,t.precision=n,t.rounding=e,i.ln()):new t(i)},S.inverseHyperbolicSine=S.asinh=function(){var n,e,i=this,t=i.constructor;return!i.isFinite()||i.isZero()?new t(i):(n=t.precision,e=t.rounding,t.precision=n+2*Math.max(Math.abs(i.e),i.sd())+6,t.rounding=1,f=!1,i=i.times(i).plus(1).sqrt().plus(i),f=!0,t.precision=n,t.rounding=e,i.ln())},S.inverseHyperbolicTangent=S.atanh=function(){var n,e,i,t,r=this,s=r.constructor;return r.isFinite()?r.e>=0?new s(r.abs().eq(1)?r.s/0:r.isZero()?r:NaN):(n=s.precision,e=s.rounding,t=r.sd(),Math.max(t,n)<2*-r.e-1?T(new s(r),n,e,!0):(s.precision=i=t-r.e,r=F(r.plus(1),new s(1).minus(r),i+n,1),s.precision=n+4,s.rounding=1,r=r.ln(),s.precision=n,s.rounding=e,r.times(.5))):new s(NaN)},S.inverseSine=S.asin=function(){var n,e,i,t,r=this,s=r.constructor;return r.isZero()?new s(r):(e=r.abs().cmp(1),i=s.precision,t=s.rounding,-1!==e?0===e?((n=P(s,i+4,t).times(.5)).s=r.s,n):new s(NaN):(s.precision=i+6,s.rounding=1,r=r.div(new s(1).minus(r.times(r)).sqrt().plus(1)).atan(),s.precision=i,s.rounding=t,r.times(2)))},S.inverseTangent=S.atan=function(){var n,e,i,t,r,s,o,u,c,h=this,a=h.constructor,l=a.precision,d=a.rounding;if(h.isFinite()){if(h.isZero())return new a(h);if(h.abs().eq(1)&&l+4<=x)return(o=P(a,l+4,d).times(.25)).s=h.s,o}else{if(!h.s)return new a(NaN);if(l+4<=x)return(o=P(a,l+4,d).times(.5)).s=h.s,o}for(a.precision=u=l+10,a.rounding=1,n=i=Math.min(28,u/7+2|0);n;--n)h=h.div(h.times(h).plus(1).sqrt().plus(1));for(f=!1,e=Math.ceil(u/7),t=1,c=h.times(h),o=new a(h),r=h;-1!==n;)if(r=r.times(c),s=o.minus(r.div(t+=2)),r=r.times(c),void 0!==(o=s.plus(r.div(t+=2))).d[e])for(n=e;o.d[n]===s.d[n]&&n--;);return i&&(o=o.times(2<<i-1)),f=!0,T(o,a.precision=l,a.rounding=d,!0)},S.isFinite=function(){return!!this.d},S.isInteger=S.isInt=function(){return!!this.d&&p(this.e/7)>this.d.length-2},S.isNaN=function(){return!this.s},S.isNegative=S.isNeg=function(){return this.s<0},S.isPositive=S.isPos=function(){return this.s>0},S.isZero=function(){return!!this.d&&0===this.d[0]},S.lessThan=S.lt=function(n){return this.cmp(n)<0},S.lessThanOrEqualTo=S.lte=function(n){return this.cmp(n)<1},S.logarithm=S.log=function(n){var e,i,t,r,s,o,u,c,h=this,a=h.constructor,l=a.precision,d=a.rounding;if(null==n)n=new a(10),e=!0;else{if(i=(n=new a(n)).d,n.s<0||!i||!i[0]||n.eq(1))return new a(NaN);e=n.eq(10)}if(i=h.d,h.s<0||!i||!i[0]||h.eq(1))return new a(i&&!i[0]?-1/0:1!=h.s?NaN:i?0:1/0);if(e)if(i.length>1)s=!0;else{for(r=i[0];r%10==0;)r/=10;s=1!==r}if(f=!1,o=$(h,u=l+5),t=e?A(a,u+10):$(n,u),q((c=F(o,t,u,1)).d,r=l,d))do{if(o=$(h,u+=10),t=e?A(a,u+10):$(n,u),c=F(o,t,u,1),!s){+M(c.d).slice(r+1,r+15)+1==1e14&&(c=T(c,l+1,0));break}}while(q(c.d,r+=10,d));return f=!0,T(c,l,d)},S.minus=S.sub=function(n){var e,i,t,r,s,o,u,c,h,a,l,d,g=this,m=g.constructor;if(n=new m(n),!g.d||!n.d)return g.s&&n.s?g.d?n.s=-n.s:n=new m(n.d||g.s!==n.s?g:NaN):n=new m(NaN),n;if(g.s!=n.s)return n.s=-n.s,g.plus(n);if(h=g.d,d=n.d,u=m.precision,c=m.rounding,!h[0]||!d[0]){if(d[0])n.s=-n.s;else{if(!h[0])return new m(3===c?-0:0);n=new m(g)}return f?T(n,u,c):n}if(i=p(n.e/7),a=p(g.e/7),h=h.slice(),s=a-i){for((l=s<0)?(e=h,s=-s,o=d.length):(e=d,i=a,o=h.length),s>(t=Math.max(Math.ceil(u/7),o)+2)&&(s=t,e.length=1),e.reverse(),t=s;t--;)e.push(0);e.reverse()}else{for((l=(t=h.length)<(o=d.length))&&(o=t),t=0;t<o;t++)if(h[t]!=d[t]){l=h[t]<d[t];break}s=0}for(l&&(e=h,h=d,d=e,n.s=-n.s),o=h.length,t=d.length-o;t>0;--t)h[o++]=0;for(t=d.length;t>s;){if(h[--t]<d[t]){for(r=t;r&&0===h[--r];)h[r]=E-1;--h[r],h[t]+=E}h[t]-=d[t]}for(;0===h[--o];)h.pop();for(;0===h[0];h.shift())--i;return h[0]?(n.d=h,n.e=U(h,i),f?T(n,u,c):n):new m(3===c?-0:0)},S.modulo=S.mod=function(n){var e,i=this,t=i.constructor;return n=new t(n),!i.d||!n.s||n.d&&!n.d[0]?new t(NaN):!n.d||i.d&&!i.d[0]?T(new t(i),t.precision,t.rounding):(f=!1,9==t.modulo?(e=F(i,n.abs(),0,3,1)).s*=n.s:e=F(i,n,0,t.modulo,1),e=e.times(n),f=!0,i.minus(e))},S.naturalExponential=S.exp=function(){return L(this)},S.naturalLogarithm=S.ln=function(){return $(this)},S.negated=S.neg=function(){var n=new this.constructor(this);return n.s=-n.s,T(n)},S.plus=S.add=function(n){var e,i,t,r,s,o,u,c,h,a,l=this,d=l.constructor;if(n=new d(n),!l.d||!n.d)return l.s&&n.s?l.d||(n=new d(n.d||l.s===n.s?l:NaN)):n=new d(NaN),n;if(l.s!=n.s)return n.s=-n.s,l.minus(n);if(h=l.d,a=n.d,u=d.precision,c=d.rounding,!h[0]||!a[0])return a[0]||(n=new d(l)),f?T(n,u,c):n;if(s=p(l.e/7),t=p(n.e/7),h=h.slice(),r=s-t){for(r<0?(i=h,r=-r,o=a.length):(i=a,t=s,o=h.length),r>(o=(s=Math.ceil(u/7))>o?s+1:o+1)&&(r=o,i.length=1),i.reverse();r--;)i.push(0);i.reverse()}for((o=h.length)-(r=a.length)<0&&(r=o,i=a,a=h,h=i),e=0;r;)e=(h[--r]=h[r]+a[r]+e)/E|0,h[r]%=E;for(e&&(h.unshift(e),++t),o=h.length;0==h[--o];)h.pop();return n.d=h,n.e=U(h,t),f?T(n,u,c):n},S.precision=S.sd=function(n){var e,i=this;if(void 0!==n&&n!==!!n&&1!==n&&0!==n)throw Error(a+n);return i.d?(e=_(i.d),n&&i.e+1>e&&(e=i.e+1)):e=NaN,e},S.round=function(){var n=this,e=n.constructor;return T(new e(n),n.e+1,e.rounding)},S.sine=S.sin=function(){var n,e,t=this,r=t.constructor;return t.isFinite()?t.isZero()?new r(t):(n=r.precision,e=r.rounding,r.precision=n+Math.max(t.e,t.sd())+7,r.rounding=1,t=function(n,e){var i,t=e.d.length;if(t<3)return e.isZero()?e:V(n,2,e,e);i=(i=1.4*Math.sqrt(t))>16?16:0|i,e=e.times(1/W(5,i)),e=V(n,2,e,e);for(var r,s=new n(5),o=new n(16),u=new n(20);i--;)r=e.times(e),e=e.times(s.plus(r.times(o.times(r).minus(u))));return e}(r,G(r,t)),r.precision=n,r.rounding=e,T(i>2?t.neg():t,n,e,!0)):new r(NaN)},S.squareRoot=S.sqrt=function(){var n,e,i,t,r,s,o=this,u=o.d,c=o.e,h=o.s,a=o.constructor;if(1!==h||!u||!u[0])return new a(!h||h<0&&(!u||u[0])?NaN:u?o:1/0);for(f=!1,0==(h=Math.sqrt(+o))||h==1/0?(((e=M(u)).length+c)%2==0&&(e+="0"),h=Math.sqrt(e),c=p((c+1)/2)-(c<0||c%2),t=new a(e=h==1/0?"5e"+c:(e=h.toExponential()).slice(0,e.indexOf("e")+1)+c)):t=new a(h.toString()),i=(c=a.precision)+3;;)if(t=(s=t).plus(F(o,s,i+2,1)).times(.5),M(s.d).slice(0,i)===(e=M(t.d)).slice(0,i)){if("9999"!=(e=e.slice(i-3,i+1))&&(r||"4999"!=e)){+e&&(+e.slice(1)||"5"!=e.charAt(0))||(T(t,c+1,1),n=!t.times(t).eq(o));break}if(!r&&(T(s,c+1,0),s.times(s).eq(o))){t=s;break}i+=4,r=1}return f=!0,T(t,c,a.rounding,n)},S.tangent=S.tan=function(){var n,e,t=this,r=t.constructor;return t.isFinite()?t.isZero()?new r(t):(n=r.precision,e=r.rounding,r.precision=n+10,r.rounding=1,(t=t.sin()).s=1,t=F(t,new r(1).minus(t.times(t)).sqrt(),n+10,0),r.precision=n,r.rounding=e,T(2==i||4==i?t.neg():t,n,e,!0)):new r(NaN)},S.times=S.mul=function(n){var e,i,t,r,s,o,u,c,h,a=this,l=a.constructor,d=a.d,g=(n=new l(n)).d;if(n.s*=a.s,!(d&&d[0]&&g&&g[0]))return new l(!n.s||d&&!d[0]&&!g||g&&!g[0]&&!d?NaN:d&&g?0*n.s:n.s/0);for(i=p(a.e/7)+p(n.e/7),(c=d.length)<(h=g.length)&&(s=d,d=g,g=s,o=c,c=h,h=o),s=[],t=o=c+h;t--;)s.push(0);for(t=h;--t>=0;){for(e=0,r=c+t;r>t;)u=s[r]+g[t]*d[r-t-1]+e,s[r--]=u%E|0,e=u/E|0;s[r]=(s[r]+e)%E|0}for(;!s[--o];)s.pop();return e?++i:s.shift(),n.d=s,n.e=U(s,i),f?T(n,l.precision,l.rounding):n},S.toBinary=function(n,e){return J(this,2,n,e)},S.toDecimalPlaces=S.toDP=function(n,e){var i=this,t=i.constructor;return i=new t(i),void 0===n?i:(O(n,0,r),void 0===e?e=t.rounding:O(e,0,8),T(i,n+i.e+1,e))},S.toExponential=function(n,e){var i,t=this,s=t.constructor;return void 0===n?i=R(t,!0):(O(n,0,r),void 0===e?e=s.rounding:O(e,0,8),i=R(t=T(new s(t),n+1,e),!0,n+1)),t.isNeg()&&!t.isZero()?"-"+i:i},S.toFixed=function(n,e){var i,t,s=this,o=s.constructor;return void 0===n?i=R(s):(O(n,0,r),void 0===e?e=o.rounding:O(e,0,8),i=R(t=T(new o(s),n+s.e+1,e),!1,n+t.e+1)),s.isNeg()&&!s.isZero()?"-"+i:i},S.toFraction=function(n){var e,i,t,r,s,o,u,c,h,l,d,g,p=this,w=p.d,v=p.constructor;if(!w)return new v(p);if(h=i=new v(1),t=c=new v(0),o=(s=(e=new v(t)).e=_(w)-p.e-1)%7,e.d[0]=m(10,o<0?7+o:o),null==n)n=s>0?e:h;else{if(!(u=new v(n)).isInt()||u.lt(h))throw Error(a+u);n=u.gt(e)?s>0?e:h:u}for(f=!1,u=new v(M(w)),l=v.precision,v.precision=s=7*w.length*2;d=F(u,e,0,1,1),1!=(r=i.plus(d.times(t))).cmp(n);)i=t,t=r,r=h,h=c.plus(d.times(r)),c=r,r=e,e=u.minus(d.times(r)),u=r;return r=F(n.minus(i),t,0,1,1),c=c.plus(r.times(h)),i=i.plus(r.times(t)),c.s=h.s=p.s,g=F(h,t,s,1).minus(p).abs().cmp(F(c,i,s,1).minus(p).abs())<1?[h,t]:[c,i],v.precision=l,f=!0,g},S.toHexadecimal=S.toHex=function(n,e){return J(this,16,n,e)},S.toNearest=function(n,e){var i=this,t=i.constructor;if(i=new t(i),null==n){if(!i.d)return i;n=new t(1),e=t.rounding}else{if(n=new t(n),void 0===e?e=t.rounding:O(e,0,8),!i.d)return n.s?i:n;if(!n.d)return n.s&&(n.s=i.s),n}return n.d[0]?(f=!1,i=F(i,n,0,e,1).times(n),f=!0,T(i)):(n.s=i.s,i=n),i},S.toNumber=function(){return+this},S.toOctal=function(n,e){return J(this,8,n,e)},S.toPower=S.pow=function(n){var e,i,t,r,s,o,u=this,c=u.constructor,h=+(n=new c(n));if(!(u.d&&n.d&&u.d[0]&&n.d[0]))return new c(m(+u,h));if((u=new c(u)).eq(1))return u;if(t=c.precision,s=c.rounding,n.eq(1))return T(u,t,s);if((e=p(n.e/7))>=n.d.length-1&&(i=h<0?-h:h)<=9007199254740991)return r=I(c,u,i,t),n.s<0?new c(1).div(r):T(r,t,s);if((o=u.s)<0){if(e<n.d.length-1)return new c(NaN);if(1&n.d[e]||(o=1),0==u.e&&1==u.d[0]&&1==u.d.length)return u.s=o,u}return(e=0!=(i=m(+u,h))&&isFinite(i)?new c(i+"").e:p(h*(Math.log("0."+M(u.d))/Math.LN10+u.e+1)))>c.maxE+1||e<c.minE-1?new c(e>0?o/0:0):(f=!1,c.rounding=u.s=1,i=Math.min(12,(e+"").length),(r=L(n.times($(u,t+i)),t)).d&&q((r=T(r,t+5,1)).d,t,s)&&(e=t+10,+M((r=T(L(n.times($(u,e+i)),e),e+5,1)).d).slice(t+1,t+15)+1==1e14&&(r=T(r,t+1,0))),r.s=o,f=!0,c.rounding=s,T(r,t,s))},S.toPrecision=function(n,e){var i,t=this,s=t.constructor;return void 0===n?i=R(t,t.e<=s.toExpNeg||t.e>=s.toExpPos):(O(n,1,r),void 0===e?e=s.rounding:O(e,0,8),i=R(t=T(new s(t),n,e),n<=t.e||t.e<=s.toExpNeg,n)),t.isNeg()&&!t.isZero()?"-"+i:i},S.toSignificantDigits=S.toSD=function(n,e){var i=this.constructor;return void 0===n?(n=i.precision,e=i.rounding):(O(n,1,r),void 0===e?e=i.rounding:O(e,0,8)),T(new i(this),n,e)},S.toString=function(){var n=this,e=n.constructor,i=R(n,n.e<=e.toExpNeg||n.e>=e.toExpPos);return n.isNeg()&&!n.isZero()?"-"+i:i},S.truncated=S.trunc=function(){return T(new this.constructor(this),this.e+1,1)},S.valueOf=S.toJSON=function(){var n=this,e=n.constructor,i=R(n,n.e<=e.toExpNeg||n.e>=e.toExpPos);return n.isNeg()?"-"+i:i};var F=function(){function n(n,e,i){var t,r=0,s=n.length;for(n=n.slice();s--;)t=n[s]*e+r,n[s]=t%i|0,r=t/i|0;return r&&n.unshift(r),n}function i(n,e,i,t){var r,s;if(i!=t)s=i>t?1:-1;else for(r=s=0;r<i;r++)if(n[r]!=e[r]){s=n[r]>e[r]?1:-1;break}return s}function t(n,e,i,t){for(var r=0;i--;)n[i]-=r,r=n[i]<e[i]?1:0,n[i]=r*t+n[i]-e[i];for(;!n[0]&&n.length>1;)n.shift()}return function(r,s,o,u,c,f){var h,a,l,d,g,m,w,v,N,b,y,x,S,M,O,q,D,F,R,U,A=r.constructor,P=r.s==s.s?1:-1,_=r.d,Z=s.d;if(!(_&&_[0]&&Z&&Z[0]))return new A(r.s&&s.s&&(_?!Z||_[0]!=Z[0]:Z)?_&&0==_[0]||!Z?0*P:P/0:NaN);for(f?(g=1,a=r.e-s.e):(f=E,g=7,a=p(r.e/g)-p(s.e/g)),R=Z.length,D=_.length,b=(N=new A(P)).d=[],l=0;Z[l]==(_[l]||0);l++);if(Z[l]>(_[l]||0)&&a--,null==o?(M=o=A.precision,u=A.rounding):M=c?o+(r.e-s.e)+1:o,M<0)b.push(1),m=!0;else{if(M=M/g+2|0,l=0,1==R){for(d=0,Z=Z[0],M++;(l<D||d)&&M--;l++)O=d*f+(_[l]||0),b[l]=O/Z|0,d=O%Z|0;m=d||l<D}else{for((d=f/(Z[0]+1)|0)>1&&(Z=n(Z,d,f),_=n(_,d,f),R=Z.length,D=_.length),q=R,x=(y=_.slice(0,R)).length;x<R;)y[x++]=0;(U=Z.slice()).unshift(0),F=Z[0],Z[1]>=f/2&&++F;do{d=0,(h=i(Z,y,R,x))<0?(S=y[0],R!=x&&(S=S*f+(y[1]||0)),(d=S/F|0)>1?(d>=f&&(d=f-1),1==(h=i(w=n(Z,d,f),y,v=w.length,x=y.length))&&(d--,t(w,R<v?U:Z,v,f))):(0==d&&(h=d=1),w=Z.slice()),(v=w.length)<x&&w.unshift(0),t(y,w,x,f),-1==h&&(h=i(Z,y,R,x=y.length))<1&&(d++,t(y,R<x?U:Z,x,f)),x=y.length):0===h&&(d++,y=[0]),b[l++]=d,h&&y[0]?y[x++]=_[q]||0:(y=[_[q]],x=1)}while((q++<D||void 0!==y[0])&&M--);m=void 0!==y[0]}b[0]||b.shift()}if(1==g)N.e=a,e=m;else{for(l=1,d=b[0];d>=10;d/=10)l++;N.e=l+a*g-1,T(N,c?o+N.e+1:o,u,m)}return N}}();function T(n,e,i,t){var r,s,o,u,c,h,a,l,d,g=n.constructor;n:if(null!=e){if(!(l=n.d))return n;for(r=1,u=l[0];u>=10;u/=10)r++;if((s=e-r)<0)s+=7,o=e,c=(a=l[d=0])/m(10,r-o-1)%10|0;else if((d=Math.ceil((s+1)/7))>=(u=l.length)){if(!t)break n;for(;u++<=d;)l.push(0);a=c=0,r=1,o=(s%=7)-7+1}else{for(a=u=l[d],r=1;u>=10;u/=10)r++;c=(o=(s%=7)-7+r)<0?0:a/m(10,r-o-1)%10|0}if(t=t||e<0||void 0!==l[d+1]||(o<0?a:a%m(10,r-o-1)),h=i<4?(c||t)&&(0==i||i==(n.s<0?3:2)):c>5||5==c&&(4==i||t||6==i&&(s>0?o>0?a/m(10,r-o):0:l[d-1])%10&1||i==(n.s<0?8:7)),e<1||!l[0])return l.length=0,h?(e-=n.e+1,l[0]=m(10,(7-e%7)%7),n.e=-e||0):l[0]=n.e=0,n;if(0==s?(l.length=d,u=1,d--):(l.length=d+1,u=m(10,7-s),l[d]=o>0?(a/m(10,r-o)%m(10,o)|0)*u:0),h)for(;;){if(0==d){for(s=1,o=l[0];o>=10;o/=10)s++;for(o=l[0]+=u,u=1;o>=10;o/=10)u++;s!=u&&(n.e++,l[0]==E&&(l[0]=1));break}if(l[d]+=u,l[d]!=E)break;l[d--]=0,u=1}for(s=l.length;0===l[--s];)l.pop()}return f&&(n.e>g.maxE?(n.d=null,n.e=NaN):n.e<g.minE&&(n.e=0,n.d=[0])),n}function R(n,e,i){if(!n.isFinite())return B(n);var t,r=n.e,s=M(n.d),o=s.length;return e?(i&&(t=i-o)>0?s=s.charAt(0)+"."+s.slice(1)+Z(t):o>1&&(s=s.charAt(0)+"."+s.slice(1)),s=s+(n.e<0?"e":"e+")+n.e):r<0?(s="0."+Z(-r-1)+s,i&&(t=i-o)>0&&(s+=Z(t))):r>=o?(s+=Z(r+1-o),i&&(t=i-r-1)>0&&(s=s+"."+Z(t))):((t=r+1)<o&&(s=s.slice(0,t)+"."+s.slice(t)),i&&(t=i-o)>0&&(r+1===o&&(s+="."),s+=Z(t))),s}function U(n,e){var i=n[0];for(e*=7;i>=10;i/=10)e++;return e}function A(n,e,i){if(e>y)throw f=!0,i&&(n.precision=i),Error(l);return T(new n(o),e,1,!0)}function P(n,e,i){if(e>x)throw Error(l);return T(new n(u),e,i,!0)}function _(n){var e=n.length-1,i=7*e+1;if(e=n[e]){for(;e%10==0;e/=10)i--;for(e=n[0];e>=10;e/=10)i++}return i}function Z(n){for(var e="";n--;)e+="0";return e}function I(n,e,i,t){var r,s=new n(1),o=Math.ceil(t/7+4);for(f=!1;;){if(i%2&&z((s=s.times(e)).d,o)&&(r=!0),0===(i=p(i/2))){i=s.d.length-1,r&&0===s.d[i]&&++s.d[i];break}z((e=e.times(e)).d,o)}return f=!0,s}function k(n){return 1&n.d[n.d.length-1]}function C(n,e,i){for(var t,r,s=new n(e[0]),o=0;++o<e.length;){if(!(r=new n(e[o])).s){s=r;break}((t=s.cmp(r))===i||0===t&&s.s===i)&&(s=r)}return s}function L(n,e){var i,t,r,s,o,u,c,h=0,a=0,l=0,d=n.constructor,g=d.rounding,p=d.precision;if(!n.d||!n.d[0]||n.e>17)return new d(n.d?n.d[0]?n.s<0?0:1/0:1:n.s?n.s<0?0:n:NaN);for(null==e?(f=!1,c=p):c=e,u=new d(.03125);n.e>-2;)n=n.times(u),l+=5;for(c+=t=Math.log(m(2,l))/Math.LN10*2+5|0,i=s=o=new d(1),d.precision=c;;){if(s=T(s.times(n),c,1),i=i.times(++a),M((u=o.plus(F(s,i,c,1))).d).slice(0,c)===M(o.d).slice(0,c)){for(r=l;r--;)o=T(o.times(o),c,1);if(null!=e)return d.precision=p,o;if(!(h<3&&q(o.d,c-t,g,h)))return T(o,d.precision=p,g,f=!0);d.precision=c+=10,i=s=u=new d(1),a=0,h++}o=u}}function $(n,e){var i,t,r,s,o,u,c,h,a,l,d,g=1,p=n,m=p.d,w=p.constructor,v=w.rounding,N=w.precision;if(p.s<0||!m||!m[0]||!p.e&&1==m[0]&&1==m.length)return new w(m&&!m[0]?-1/0:1!=p.s?NaN:m?0:p);if(null==e?(f=!1,a=N):a=e,w.precision=a+=10,t=(i=M(m)).charAt(0),!(Math.abs(s=p.e)<15e14))return h=A(w,a+2,N).times(s+""),p=$(new w(t+"."+i.slice(1)),a-10).plus(h),w.precision=N,null==e?T(p,N,v,f=!0):p;for(;t<7&&1!=t||1==t&&i.charAt(1)>3;)t=(i=M((p=p.times(n)).d)).charAt(0),g++;for(s=p.e,t>1?(p=new w("0."+i),s++):p=new w(t+"."+i.slice(1)),l=p,c=o=p=F(p.minus(1),p.plus(1),a,1),d=T(p.times(p),a,1),r=3;;){if(o=T(o.times(d),a,1),M((h=c.plus(F(o,new w(r),a,1))).d).slice(0,a)===M(c.d).slice(0,a)){if(c=c.times(2),0!==s&&(c=c.plus(A(w,a+2,N).times(s+""))),c=F(c,new w(g),a,1),null!=e)return w.precision=N,c;if(!q(c.d,a-10,v,u))return T(c,w.precision=N,v,f=!0);w.precision=a+=10,h=o=p=F(l.minus(1),l.plus(1),a,1),d=T(p.times(p),a,1),r=u=1}c=h,r+=2}}function B(n){return String(n.s*n.s/0)}function H(n,e){var i,t,r;for((i=e.indexOf("."))>-1&&(e=e.replace(".","")),(t=e.search(/e/i))>0?(i<0&&(i=t),i+=+e.slice(t+1),e=e.substring(0,t)):i<0&&(i=e.length),t=0;48===e.charCodeAt(t);t++);for(r=e.length;48===e.charCodeAt(r-1);--r);if(e=e.slice(t,r)){if(r-=t,n.e=i=i-t-1,n.d=[],t=(i+1)%7,i<0&&(t+=7),t<r){for(t&&n.d.push(+e.slice(0,t)),r-=7;t<r;)n.d.push(+e.slice(t,t+=7));t=7-(e=e.slice(t)).length}else t-=r;for(;t--;)e+="0";n.d.push(+e),f&&(n.e>n.constructor.maxE?(n.d=null,n.e=NaN):n.e<n.constructor.minE&&(n.e=0,n.d=[0]))}else n.e=0,n.d=[0];return n}function j(n,e){var i,t,r,s,o,u,c,h,l;if(e.indexOf("_")>-1){if(e=e.replace(/(\d)_(?=\d)/g,"$1"),b.test(e))return H(n,e)}else if("Infinity"===e||"NaN"===e)return+e||(n.s=NaN),n.e=NaN,n.d=null,n;if(v.test(e))i=16,e=e.toLowerCase();else if(w.test(e))i=2;else{if(!N.test(e))throw Error(a+e);i=8}for((s=e.search(/p/i))>0?(c=+e.slice(s+1),e=e.substring(2,s)):e=e.slice(2),o=(s=e.indexOf("."))>=0,t=n.constructor,o&&(s=(u=(e=e.replace(".","")).length)-s,r=I(t,new t(i),s,2*s)),s=l=(h=D(e,i,E)).length-1;0===h[s];--s)h.pop();return s<0?new t(0*n.s):(n.e=U(h,l),n.d=h,f=!1,o&&(n=F(n,r,4*u)),c&&(n=n.times(Math.abs(c)<54?m(2,c):In.pow(2,c))),f=!0,n)}function V(n,e,i,t,r){var s,o,u,c,h=n.precision,a=Math.ceil(h/7);for(f=!1,c=i.times(i),u=new n(t);;){if(o=F(u.times(c),new n(e++*e++),h,1),u=r?t.plus(o):t.minus(o),t=F(o.times(c),new n(e++*e++),h,1),void 0!==(o=u.plus(t)).d[a]){for(s=a;o.d[s]===u.d[s]&&s--;);if(-1==s)break}s=u,u=t,t=o,o=s}return f=!0,o.d.length=a+1,o}function W(n,e){for(var i=n;--e;)i*=n;return i}function G(n,e){var t,r=e.s<0,s=P(n,n.precision,1),o=s.times(.5);if((e=e.abs()).lte(o))return i=r?4:1,e;if((t=e.divToInt(s)).isZero())i=r?3:2;else{if((e=e.minus(t.times(s))).lte(o))return i=k(t)?r?2:3:r?4:1,e;i=k(t)?r?1:4:r?3:2}return e.minus(s).abs()}function J(n,i,t,o){var u,c,f,h,a,l,d,g,p,m=n.constructor,w=void 0!==t;if(w?(O(t,1,r),void 0===o?o=m.rounding:O(o,0,8)):(t=m.precision,o=m.rounding),n.isFinite()){for(w?(u=2,16==i?t=4*t-3:8==i&&(t=3*t-2)):u=i,(f=(d=R(n)).indexOf("."))>=0&&(d=d.replace(".",""),(p=new m(1)).e=d.length-f,p.d=D(R(p),10,u),p.e=p.d.length),c=a=(g=D(d,10,u)).length;0==g[--a];)g.pop();if(g[0]){if(f<0?c--:((n=new m(n)).d=g,n.e=c,g=(n=F(n,p,t,o,0,u)).d,c=n.e,l=e),f=g[t],h=u/2,l=l||void 0!==g[t+1],l=o<4?(void 0!==f||l)&&(0===o||o===(n.s<0?3:2)):f>h||f===h&&(4===o||l||6===o&&1&g[t-1]||o===(n.s<0?8:7)),g.length=t,l)for(;++g[--t]>u-1;)g[t]=0,t||(++c,g.unshift(1));for(a=g.length;!g[a-1];--a);for(f=0,d="";f<a;f++)d+=s.charAt(g[f]);if(w){if(a>1)if(16==i||8==i){for(f=16==i?4:3,--a;a%f;a++)d+="0";for(a=(g=D(d,u,i)).length;!g[a-1];--a);for(f=1,d="1.";f<a;f++)d+=s.charAt(g[f])}else d=d.charAt(0)+"."+d.slice(1);d=d+(c<0?"p":"p+")+c}else if(c<0){for(;++c;)d="0"+d;d="0."+d}else if(++c>a)for(c-=a;c--;)d+="0";else c<a&&(d=d.slice(0,c)+"."+d.slice(c))}else d=w?"0p+0":"0";d=(16==i?"0x":2==i?"0b":8==i?"0o":"")+d}else d=B(n);return n.s<0?"-"+d:d}function z(n,e){if(n.length>e)return n.length=e,!0}function K(n){return new this(n).abs()}function Q(n){return new this(n).acos()}function X(n){return new this(n).acosh()}function Y(n,e){return new this(n).plus(e)}function nn(n){return new this(n).asin()}function en(n){return new this(n).asinh()}function tn(n){return new this(n).atan()}function rn(n){return new this(n).atanh()}function sn(n,e){n=new this(n),e=new this(e);var i,t=this.precision,r=this.rounding,s=t+4;return n.s&&e.s?n.d||e.d?!e.d||n.isZero()?(i=e.s<0?P(this,t,r):new this(0)).s=n.s:!n.d||e.isZero()?(i=P(this,s,1).times(.5)).s=n.s:e.s<0?(this.precision=s,this.rounding=1,i=this.atan(F(n,e,s,1)),e=P(this,s,1),this.precision=t,this.rounding=r,i=n.s<0?i.minus(e):i.plus(e)):i=this.atan(F(n,e,s,1)):(i=P(this,s,1).times(e.s>0?.25:.75)).s=n.s:i=new this(NaN),i}function on(n){return new this(n).cbrt()}function un(n){return T(n=new this(n),n.e+1,2)}function cn(n,e,i){return new this(n).clamp(e,i)}function fn(n){if(!n||"object"!=typeof n)throw Error(h+"Object expected");var e,i,s,o=!0===n.defaults,u=["precision",1,r,"rounding",0,8,"toExpNeg",-9e15,0,"toExpPos",0,t,"maxE",0,t,"minE",-9e15,0,"modulo",0,9];for(e=0;e<u.length;e+=3)if(i=u[e],o&&(this[i]=c[i]),void 0!==(s=n[i])){if(!(p(s)===s&&s>=u[e+1]&&s<=u[e+2]))throw Error(a+i+": "+s);this[i]=s}if(i="crypto",o&&(this[i]=c[i]),void 0!==(s=n[i])){if(!0!==s&&!1!==s&&0!==s&&1!==s)throw Error(a+i+": "+s);if(s){if("undefined"==typeof crypto||!crypto||!crypto.getRandomValues&&!crypto.randomBytes)throw Error(d);this[i]=!0}else this[i]=!1}return this}function hn(n){return new this(n).cos()}function an(n){return new this(n).cosh()}function ln(n,e){return new this(n).div(e)}function dn(n){return new this(n).exp()}function gn(n){return T(n=new this(n),n.e+1,3)}function pn(){var n,e,i=new this(0);for(f=!1,n=0;n<arguments.length;)if((e=new this(arguments[n++])).d)i.d&&(i=i.plus(e.times(e)));else{if(e.s)return f=!0,new this(1/0);i=e}return f=!0,i.sqrt()}function mn(n){return n instanceof In||n&&n.toStringTag===g||!1}function wn(n){return new this(n).ln()}function vn(n,e){return new this(n).log(e)}function Nn(n){return new this(n).log(2)}function bn(n){return new this(n).log(10)}function En(){return C(this,arguments,-1)}function yn(){return C(this,arguments,1)}function xn(n,e){return new this(n).mod(e)}function Sn(n,e){return new this(n).mul(e)}function Mn(n,e){return new this(n).pow(e)}function On(n){var e,i,t,s,o=0,u=new this(1),c=[];if(void 0===n?n=this.precision:O(n,1,r),t=Math.ceil(n/7),this.crypto)if(crypto.getRandomValues)for(e=crypto.getRandomValues(new Uint32Array(t));o<t;)(s=e[o])>=429e7?e[o]=crypto.getRandomValues(new Uint32Array(1))[0]:c[o++]=s%1e7;else{if(!crypto.randomBytes)throw Error(d);for(e=crypto.randomBytes(t*=4);o<t;)(s=e[o]+(e[o+1]<<8)+(e[o+2]<<16)+((127&e[o+3])<<24))>=214e7?crypto.randomBytes(4).copy(e,o):(c.push(s%1e7),o+=4);o=t/4}else for(;o<t;)c[o++]=1e7*Math.random()|0;for(n%=7,(t=c[--o])&&n&&(s=m(10,7-n),c[o]=(t/s|0)*s);0===c[o];o--)c.pop();if(o<0)i=0,c=[0];else{for(i=-1;0===c[0];i-=7)c.shift();for(t=1,s=c[0];s>=10;s/=10)t++;t<7&&(i-=7-t)}return u.e=i,u.d=c,u}function qn(n){return T(n=new this(n),n.e+1,this.rounding)}function Dn(n){return(n=new this(n)).d?n.d[0]?n.s:0*n.s:n.s||NaN}function Fn(n){return new this(n).sin()}function Tn(n){return new this(n).sinh()}function Rn(n){return new this(n).sqrt()}function Un(n,e){return new this(n).sub(e)}function An(){var n=0,e=arguments,i=new this(e[n]);for(f=!1;i.s&&++n<e.length;)i=i.plus(e[n]);return f=!0,T(i,this.precision,this.rounding)}function Pn(n){return new this(n).tan()}function _n(n){return new this(n).tanh()}function Zn(n){return T(n=new this(n),n.e+1,1)}S[Symbol.for("nodejs.util.inspect.custom")]=S.toString,S[Symbol.toStringTag]="Decimal";var In=S.constructor=function n(e){var i,t,r;function s(n){var e,i,t,r=this;if(!(r instanceof s))return new s(n);if(r.constructor=s,mn(n))return r.s=n.s,void(f?!n.d||n.e>s.maxE?(r.e=NaN,r.d=null):n.e<s.minE?(r.e=0,r.d=[0]):(r.e=n.e,r.d=n.d.slice()):(r.e=n.e,r.d=n.d?n.d.slice():n.d));if("number"===(t=typeof n)){if(0===n)return r.s=1/n<0?-1:1,r.e=0,void(r.d=[0]);if(n<0?(n=-n,r.s=-1):r.s=1,n===~~n&&n<1e7){for(e=0,i=n;i>=10;i/=10)e++;return void(f?e>s.maxE?(r.e=NaN,r.d=null):e<s.minE?(r.e=0,r.d=[0]):(r.e=e,r.d=[n]):(r.e=e,r.d=[n]))}return 0*n!=0?(n||(r.s=NaN),r.e=NaN,void(r.d=null)):H(r,n.toString())}if("string"===t)return 45===(i=n.charCodeAt(0))?(n=n.slice(1),r.s=-1):(43===i&&(n=n.slice(1)),r.s=1),b.test(n)?H(r,n):j(r,n);if("bigint"===t)return n<0?(n=-n,r.s=-1):r.s=1,H(r,n.toString());throw Error(a+n)}if(s.prototype=S,s.ROUND_UP=0,s.ROUND_DOWN=1,s.ROUND_CEIL=2,s.ROUND_FLOOR=3,s.ROUND_HALF_UP=4,s.ROUND_HALF_DOWN=5,s.ROUND_HALF_EVEN=6,s.ROUND_HALF_CEIL=7,s.ROUND_HALF_FLOOR=8,s.EUCLID=9,s.config=s.set=fn,s.clone=n,s.isDecimal=mn,s.abs=K,s.acos=Q,s.acosh=X,s.add=Y,s.asin=nn,s.asinh=en,s.atan=tn,s.atanh=rn,s.atan2=sn,s.cbrt=on,s.ceil=un,s.clamp=cn,s.cos=hn,s.cosh=an,s.div=ln,s.exp=dn,s.floor=gn,s.hypot=pn,s.ln=wn,s.log=vn,s.log10=bn,s.log2=Nn,s.max=En,s.min=yn,s.mod=xn,s.mul=Sn,s.pow=Mn,s.random=On,s.round=qn,s.sign=Dn,s.sin=Fn,s.sinh=Tn,s.sqrt=Rn,s.sub=Un,s.sum=An,s.tan=Pn,s.tanh=_n,s.trunc=Zn,void 0===e&&(e={}),e&&!0!==e.defaults)for(r=["precision","rounding","toExpNeg","toExpPos","maxE","minE","modulo","crypto"],i=0;i<r.length;)e.hasOwnProperty(t=r[i++])||(e[t]=this[t]);return s.config(e),s}(c);o=new In(o),u=new In(u);
|
|
9
|
+
/*!
|
|
10
|
+
* smart-unit
|
|
11
|
+
* Copyright (c) [2026] [flycran]
|
|
12
|
+
* MIT License. See LICENSE for details.
|
|
13
|
+
*/
|
|
14
|
+
const kn="Accepting NaN as an argument may be unintentional and could lead to invalid results. If this is intentional, please set `SmartUnit.ignoreNaNInputs` to `true`.",Cn="By default, only number input is supported. To enable high-precision calculations, explicitly set the decimalSafety parameter to true.";class Ln{constructor(n,e={}){if(this.units=n,this.unitsStr=[],this.DecimalClass=In,!n.length)throw new Error("units is empty.");if(this.threshold=e.threshold||1,this.decimal=e.fractionDigits,this.highPrecision=e.useDecimal,e.decimalOptions&&(this.DecimalClass=In.clone(e.decimalOptions)),e.baseDigit){const i=[];for(let t=0;t<n.length;t++)this.unitsStr.push(n[t].toString()),i.push(n[t],e.baseDigit);this.units=i.slice(0,-1)}else{for(let e=0;e<n.length;e+=2)this.unitsStr.push(n[e].toString());this.units=n}}getUnit(n){if(!Ln.ignoreNaNInputs&&Number.isNaN(n))throw new Error(kn);let e=1;if(this.highPrecision){const i=new this.DecimalClass("bigint"==typeof n?n.toString():n),t=i.isNegative();let r=t?i.abs():i;for(;e<this.units.length-1;){const n=this.units[e];if("string"==typeof n)throw new Error(`The unit setting is incorrect; the element at index [${e}] should be of numeric type.`);if(r.lt(n*this.threshold))break;r=r.dividedBy(n),e+=2}const s=t?r.neg():r;return{num:s.toNumber(),decimal:s,unit:this.units[e-1].toString()}}{if("number"!=typeof n)throw new Error(Cn);const i=n<0;let t=i?-n:n;for(;e<this.units.length-1;){const n=this.units[e];if("string"==typeof n)throw new Error(`The unit setting is incorrect; the element at index [${e}] should be of numeric type.`);if(t<n*this.threshold)break;t/=n,e+=2}return{num:i?-t:t,unit:this.units[e-1].toString()}}}format(n,e=this.decimal){const{num:i,unit:t,decimal:r}=this.getUnit(n);let s;if("number"==typeof e)s=(null!=r?r:i).toFixed(e);else if("string"==typeof e){const[n,t]=e.split("-"),o=(i.toString().split(".")[1]||"").length,u=n?+n:-1/0,c=t?+t:1/0;s=o<u?(null!=r?r:i).toFixed(u):o>c?(null!=r?r:i).toFixed(c):(null!=r?r:i).toString()}else s=(null!=r?r:i).toString();return`${s}${t}`}toBase(n,e){if(!Ln.ignoreNaNInputs&&Number.isNaN(n))throw new Error(kn);let i=0;if(this.highPrecision){let t=new this.DecimalClass("bigint"==typeof n?n.toString():n);for(;i<this.units.length;){if(this.units[i]===e)return t;if(void 0===this.units[i])break;const n=this.units[i+1];if("number"!=typeof n)throw Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);t=t.times(n),i+=2}}else{if("number"!=typeof n)throw new Error(Cn);let t=n;for(;i<this.units.length;){if(this.units[i]===e)return t;if(void 0===this.units[i+1])break;if("number"!=typeof this.units[i+1])throw Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);t*=this.units[i+1],i+=2}}throw new Error(`Undefined unit: "${e}".`)}splitUnit(n){const e=new RegExp(`^(\\d+(?:\\.\\d+)?)(${this.unitsStr.map((n=>`${n}`)).join("|")})`),[,i,t]=n.match(e)||[];if(void 0===i||void 0===t)throw new Error(`Undefined unit: "${n}".`);return{num:+i,unit:t,decimal:this.highPrecision?new this.DecimalClass(i):void 0}}parse(n){const{num:e,unit:i,decimal:t}=this.splitUnit(n);return this.toBase(null!=t?t:e,i)}fromUnitFormat(n,e,i){const t=this.toBase(n,e);return this.format(t,i)}}Ln.ignoreNaNInputs=!1,n.ERROR_HIGH_PRECISION_NOT_ENABLED=Cn,n.ERROR_NAN_INPUT=kn,n.SmartUnit=Ln,n.default=Ln,Object.defineProperty(n,"__esModule",{value:!0})}));
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* smart-unit
|
|
3
|
+
* Copyright (c) [2026] [flycran]
|
|
4
|
+
* MIT License. See LICENSE for details.
|
|
5
|
+
*/
|
|
6
|
+
import { type Decimal } from 'decimal.js';
|
|
7
|
+
export type FractionDigits = number | `-${number}` | `${number}-` | `${number}-${number}` | undefined;
|
|
8
|
+
export type DecimalOptions = Decimal.Config;
|
|
9
|
+
export interface SmartUnitOptions<HP extends boolean = false> {
|
|
10
|
+
/** Base digit for auto-generating unit conversions */
|
|
11
|
+
baseDigit?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Threshold for unit switching
|
|
14
|
+
* The comparison value is multiplied by this threshold
|
|
15
|
+
*/
|
|
16
|
+
threshold?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Number of decimal places to preserve in the result
|
|
19
|
+
* Can be a fixed number or a range like "min-max"
|
|
20
|
+
*/
|
|
21
|
+
fractionDigits?: FractionDigits;
|
|
22
|
+
/**
|
|
23
|
+
* Enable high-precision calculation using decimal.js
|
|
24
|
+
* - Uses decimal.js for high-precision floating-point calculations
|
|
25
|
+
* - Supports calculations beyond JavaScript's safe integer limit
|
|
26
|
+
* - Enables string, BigInt, and Decimal inputs for format and other methods
|
|
27
|
+
*/
|
|
28
|
+
useDecimal?: HP;
|
|
29
|
+
/**
|
|
30
|
+
* Decimal.js configuration options
|
|
31
|
+
* - Creates an isolated Decimal class for this SmartUnit instance only
|
|
32
|
+
* - Used to customize precision and other parameters
|
|
33
|
+
*/
|
|
34
|
+
decimalOptions?: DecimalOptions;
|
|
35
|
+
}
|
|
36
|
+
export interface NumUnit {
|
|
37
|
+
/** The numeric value */
|
|
38
|
+
num: number;
|
|
39
|
+
/** The Decimal instance for high-precision mode */
|
|
40
|
+
decimal?: Decimal;
|
|
41
|
+
/** The unit string */
|
|
42
|
+
unit: string;
|
|
43
|
+
}
|
|
44
|
+
export type Num<DS extends boolean = false> = DS extends true ? number | bigint | string | Decimal : number;
|
|
45
|
+
export declare const ERROR_NAN_INPUT = "Accepting NaN as an argument may be unintentional and could lead to invalid results. If this is intentional, please set `SmartUnit.ignoreNaNInputs` to `true`.";
|
|
46
|
+
export declare const ERROR_HIGH_PRECISION_NOT_ENABLED = "By default, only number input is supported. To enable high-precision calculations, explicitly set the decimalSafety parameter to true.";
|
|
47
|
+
export declare class SmartUnit<HP extends boolean = false> {
|
|
48
|
+
readonly units: (string | number)[];
|
|
49
|
+
static ignoreNaNInputs: boolean;
|
|
50
|
+
readonly threshold: number;
|
|
51
|
+
readonly decimal?: FractionDigits;
|
|
52
|
+
readonly unitsStr: string[];
|
|
53
|
+
readonly highPrecision: HP;
|
|
54
|
+
private DecimalClass;
|
|
55
|
+
constructor(units: (string | number)[], option?: SmartUnitOptions<HP>);
|
|
56
|
+
/**
|
|
57
|
+
* Gets the appropriate unit and adjusted value for the input number
|
|
58
|
+
*
|
|
59
|
+
* @param num - The input number to determine the unit for
|
|
60
|
+
* @returns An object containing the adjusted number and its corresponding unit
|
|
61
|
+
*/
|
|
62
|
+
getUnit(num: Num<HP>): NumUnit;
|
|
63
|
+
/**
|
|
64
|
+
* Formats a number as a string with optional decimal place configuration
|
|
65
|
+
*
|
|
66
|
+
* @param num - The number to convert to string
|
|
67
|
+
* @param decimal - Decimal precision configuration (defaults to instance setting)
|
|
68
|
+
* - If a number, defines fixed decimal places
|
|
69
|
+
* - If a string in "min-max" format, defines a range of decimal places
|
|
70
|
+
* - If omitted, uses the instance's default decimal configuration
|
|
71
|
+
* @returns The formatted string representation with unit
|
|
72
|
+
*/
|
|
73
|
+
format(num: Num<HP>, decimal?: FractionDigits): string;
|
|
74
|
+
/**
|
|
75
|
+
* Converts a value from the specified unit to the base unit
|
|
76
|
+
*
|
|
77
|
+
* @param num - The number to convert
|
|
78
|
+
* @param unit - The original unit of the number
|
|
79
|
+
* @returns The converted value in base unit
|
|
80
|
+
* - Returns Decimal if high-precision mode is enabled
|
|
81
|
+
*/
|
|
82
|
+
toBase(num: Num<HP>, unit: string): HP extends true ? Decimal : number;
|
|
83
|
+
/**
|
|
84
|
+
* Splits a string into its numeric part and unit
|
|
85
|
+
*
|
|
86
|
+
* @param str - Input string containing a number followed by a unit
|
|
87
|
+
* @returns An object containing the numeric value and unit
|
|
88
|
+
* Only supports predefined units
|
|
89
|
+
* Throws an error if no match is found
|
|
90
|
+
*/
|
|
91
|
+
splitUnit(str: string): NumUnit;
|
|
92
|
+
/**
|
|
93
|
+
* Parses a string with unit into a base unit numeric value
|
|
94
|
+
*
|
|
95
|
+
* @param str - Input string containing a number and unit
|
|
96
|
+
* @returns The value converted to base unit
|
|
97
|
+
* - Returns Decimal if high-precision mode is enabled
|
|
98
|
+
*/
|
|
99
|
+
parse(str: string): HP extends true ? Decimal : number;
|
|
100
|
+
/**
|
|
101
|
+
* Converts a value from the original unit to the optimal unit with optional decimal precision
|
|
102
|
+
*
|
|
103
|
+
* @param num - The number to convert
|
|
104
|
+
* @param unit - The original unit
|
|
105
|
+
* @param decimal - Optional decimal places for formatting output
|
|
106
|
+
* @returns The converted number as a formatted string
|
|
107
|
+
*/
|
|
108
|
+
fromUnitFormat(num: Num<HP>, unit: string, decimal?: FractionDigits): string;
|
|
109
|
+
}
|
|
110
|
+
export default SmartUnit;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import DecimalConstructor from 'decimal.js';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* smart-unit
|
|
5
|
+
* Copyright (c) [2026] [flycran]
|
|
6
|
+
* MIT License. See LICENSE for details.
|
|
7
|
+
*/
|
|
8
|
+
const ERROR_NAN_INPUT = 'Accepting NaN as an argument may be unintentional and could lead to invalid results. If this is intentional, please set `SmartUnit.ignoreNaNInputs` to `true`.';
|
|
9
|
+
const ERROR_HIGH_PRECISION_NOT_ENABLED = 'By default, only number input is supported. To enable high-precision calculations, explicitly set the decimalSafety parameter to true.';
|
|
10
|
+
class SmartUnit {
|
|
11
|
+
constructor(units, option = {}) {
|
|
12
|
+
this.units = units;
|
|
13
|
+
this.unitsStr = [];
|
|
14
|
+
this.DecimalClass = DecimalConstructor;
|
|
15
|
+
if (!units.length)
|
|
16
|
+
throw new Error('units is empty.');
|
|
17
|
+
this.threshold = option.threshold || 1;
|
|
18
|
+
this.decimal = option.fractionDigits;
|
|
19
|
+
this.highPrecision = option.useDecimal;
|
|
20
|
+
if (option.decimalOptions) {
|
|
21
|
+
this.DecimalClass = DecimalConstructor.clone(option.decimalOptions);
|
|
22
|
+
}
|
|
23
|
+
if (option.baseDigit) {
|
|
24
|
+
const us = [];
|
|
25
|
+
for (let i = 0; i < units.length; i++) {
|
|
26
|
+
this.unitsStr.push(units[i].toString());
|
|
27
|
+
us.push(units[i], option.baseDigit);
|
|
28
|
+
}
|
|
29
|
+
this.units = us.slice(0, -1);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
for (let i = 0; i < units.length; i += 2) {
|
|
33
|
+
this.unitsStr.push(units[i].toString());
|
|
34
|
+
}
|
|
35
|
+
this.units = units;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// 根据输入数值获取单位和调整后的值
|
|
39
|
+
/**
|
|
40
|
+
* Gets the appropriate unit and adjusted value for the input number
|
|
41
|
+
*
|
|
42
|
+
* @param num - The input number to determine the unit for
|
|
43
|
+
* @returns An object containing the adjusted number and its corresponding unit
|
|
44
|
+
*/
|
|
45
|
+
getUnit(num) {
|
|
46
|
+
if (!SmartUnit.ignoreNaNInputs && Number.isNaN(num))
|
|
47
|
+
throw new Error(ERROR_NAN_INPUT);
|
|
48
|
+
let i = 1;
|
|
49
|
+
if (this.highPrecision) {
|
|
50
|
+
const dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
|
|
51
|
+
const isNegative = dn.isNegative();
|
|
52
|
+
let absDn = isNegative ? dn.abs() : dn;
|
|
53
|
+
while (i < this.units.length - 1) {
|
|
54
|
+
const n = this.units[i];
|
|
55
|
+
if (typeof n === 'string')
|
|
56
|
+
throw new Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
|
|
57
|
+
if (absDn.lt(n * this.threshold)) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
absDn = absDn.dividedBy(n);
|
|
61
|
+
i += 2;
|
|
62
|
+
}
|
|
63
|
+
const result = isNegative ? absDn.neg() : absDn;
|
|
64
|
+
return {
|
|
65
|
+
num: result.toNumber(),
|
|
66
|
+
decimal: result,
|
|
67
|
+
unit: this.units[i - 1].toString(),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
if (typeof num !== 'number')
|
|
72
|
+
throw new Error(ERROR_HIGH_PRECISION_NOT_ENABLED);
|
|
73
|
+
const isNegative = num < 0;
|
|
74
|
+
let absNum = isNegative ? -num : num;
|
|
75
|
+
while (i < this.units.length - 1) {
|
|
76
|
+
const n = this.units[i];
|
|
77
|
+
if (typeof n === 'string')
|
|
78
|
+
throw new Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
|
|
79
|
+
if (absNum < n * this.threshold) {
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
absNum /= n;
|
|
83
|
+
i += 2;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
num: isNegative ? -absNum : absNum,
|
|
87
|
+
unit: this.units[i - 1].toString(),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// 将数字转换为字符串表示形式,并可选择配置小数位数
|
|
92
|
+
/**
|
|
93
|
+
* Formats a number as a string with optional decimal place configuration
|
|
94
|
+
*
|
|
95
|
+
* @param num - The number to convert to string
|
|
96
|
+
* @param decimal - Decimal precision configuration (defaults to instance setting)
|
|
97
|
+
* - If a number, defines fixed decimal places
|
|
98
|
+
* - If a string in "min-max" format, defines a range of decimal places
|
|
99
|
+
* - If omitted, uses the instance's default decimal configuration
|
|
100
|
+
* @returns The formatted string representation with unit
|
|
101
|
+
*/
|
|
102
|
+
format(num, decimal = this.decimal) {
|
|
103
|
+
const { num: n, unit, decimal: dec, } = this.getUnit(num);
|
|
104
|
+
let ns;
|
|
105
|
+
if (typeof decimal === 'number') {
|
|
106
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toFixed(decimal);
|
|
107
|
+
}
|
|
108
|
+
else if (typeof decimal === 'string') {
|
|
109
|
+
const [dp1, dp2] = decimal
|
|
110
|
+
.split('-');
|
|
111
|
+
const ndp = (n.toString().split('.')[1] || '').length;
|
|
112
|
+
const minDp = dp1 ? +dp1 : -Infinity;
|
|
113
|
+
const maxDp = dp2 ? +dp2 : Infinity;
|
|
114
|
+
if (ndp < minDp) {
|
|
115
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toFixed(minDp);
|
|
116
|
+
}
|
|
117
|
+
else if (ndp > maxDp) {
|
|
118
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toFixed(maxDp);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toString();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toString();
|
|
126
|
+
}
|
|
127
|
+
return `${ns}${unit}`;
|
|
128
|
+
}
|
|
129
|
+
// 将给定数值从指定单位转换为基本单位
|
|
130
|
+
/**
|
|
131
|
+
* Converts a value from the specified unit to the base unit
|
|
132
|
+
*
|
|
133
|
+
* @param num - The number to convert
|
|
134
|
+
* @param unit - The original unit of the number
|
|
135
|
+
* @returns The converted value in base unit
|
|
136
|
+
* - Returns Decimal if high-precision mode is enabled
|
|
137
|
+
*/
|
|
138
|
+
toBase(num, unit) {
|
|
139
|
+
if (!SmartUnit.ignoreNaNInputs && Number.isNaN(num))
|
|
140
|
+
throw new Error(ERROR_NAN_INPUT);
|
|
141
|
+
let i = 0;
|
|
142
|
+
if (this.highPrecision) {
|
|
143
|
+
// High-precision calculation
|
|
144
|
+
let dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
|
|
145
|
+
while (i < this.units.length) {
|
|
146
|
+
if (this.units[i] === unit) {
|
|
147
|
+
return dn;
|
|
148
|
+
}
|
|
149
|
+
if (typeof this.units[i] === 'undefined') {
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
const cn = this.units[i + 1];
|
|
153
|
+
if (typeof cn !== 'number')
|
|
154
|
+
throw Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
|
|
155
|
+
dn = dn.times(cn);
|
|
156
|
+
i += 2;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
if (typeof num !== 'number')
|
|
161
|
+
throw new Error(ERROR_HIGH_PRECISION_NOT_ENABLED);
|
|
162
|
+
let nn = num;
|
|
163
|
+
// Normal calculation
|
|
164
|
+
while (i < this.units.length) {
|
|
165
|
+
if (this.units[i] === unit) {
|
|
166
|
+
return nn;
|
|
167
|
+
}
|
|
168
|
+
if (typeof this.units[i + 1] === 'undefined') {
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
if (typeof this.units[i + 1] !== 'number')
|
|
172
|
+
throw Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
|
|
173
|
+
nn *= this.units[i + 1];
|
|
174
|
+
i += 2;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
throw new Error(`Undefined unit: "${unit}".`);
|
|
178
|
+
}
|
|
179
|
+
// 从给定字符串中分离出数字部分和单位
|
|
180
|
+
/**
|
|
181
|
+
* Splits a string into its numeric part and unit
|
|
182
|
+
*
|
|
183
|
+
* @param str - Input string containing a number followed by a unit
|
|
184
|
+
* @returns An object containing the numeric value and unit
|
|
185
|
+
* Only supports predefined units
|
|
186
|
+
* Throws an error if no match is found
|
|
187
|
+
*/
|
|
188
|
+
splitUnit(str) {
|
|
189
|
+
const re = new RegExp(`^(\\d+(?:\\.\\d+)?)(${this.unitsStr.map(u => `${u}`).join('|')})`);
|
|
190
|
+
const [, num, unit] = str.match(re) || [];
|
|
191
|
+
if (num === undefined || unit === undefined) {
|
|
192
|
+
throw new Error(`Undefined unit: "${str}".`);
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
num: +num,
|
|
196
|
+
unit,
|
|
197
|
+
decimal: this.highPrecision ? new this.DecimalClass(num) : undefined,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
// 将带单位的值转换为基础单位的数值
|
|
201
|
+
/**
|
|
202
|
+
* Parses a string with unit into a base unit numeric value
|
|
203
|
+
*
|
|
204
|
+
* @param str - Input string containing a number and unit
|
|
205
|
+
* @returns The value converted to base unit
|
|
206
|
+
* - Returns Decimal if high-precision mode is enabled
|
|
207
|
+
*/
|
|
208
|
+
parse(str) {
|
|
209
|
+
const { num, unit, decimal, } = this.splitUnit(str);
|
|
210
|
+
return this.toBase((decimal !== null && decimal !== undefined ? decimal : num), unit);
|
|
211
|
+
}
|
|
212
|
+
// 将给定数值从原单位转换为最佳单位,并可指定小数精度
|
|
213
|
+
/**
|
|
214
|
+
* Converts a value from the original unit to the optimal unit with optional decimal precision
|
|
215
|
+
*
|
|
216
|
+
* @param num - The number to convert
|
|
217
|
+
* @param unit - The original unit
|
|
218
|
+
* @param decimal - Optional decimal places for formatting output
|
|
219
|
+
* @returns The converted number as a formatted string
|
|
220
|
+
*/
|
|
221
|
+
fromUnitFormat(num, unit, decimal) {
|
|
222
|
+
const nnum = this.toBase(num, unit);
|
|
223
|
+
return this.format(nnum, decimal);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
SmartUnit.ignoreNaNInputs = false;
|
|
227
|
+
|
|
228
|
+
export { ERROR_HIGH_PRECISION_NOT_ENABLED, ERROR_NAN_INPUT, SmartUnit, SmartUnit as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var DecimalConstructor = require('decimal.js');
|
|
6
|
+
|
|
7
|
+
/*!
|
|
8
|
+
* smart-unit
|
|
9
|
+
* Copyright (c) [2026] [flycran]
|
|
10
|
+
* MIT License. See LICENSE for details.
|
|
11
|
+
*/
|
|
12
|
+
const ERROR_NAN_INPUT = 'Accepting NaN as an argument may be unintentional and could lead to invalid results. If this is intentional, please set `SmartUnit.ignoreNaNInputs` to `true`.';
|
|
13
|
+
const ERROR_HIGH_PRECISION_NOT_ENABLED = 'By default, only number input is supported. To enable high-precision calculations, explicitly set the decimalSafety parameter to true.';
|
|
14
|
+
class SmartUnit {
|
|
15
|
+
constructor(units, option = {}) {
|
|
16
|
+
this.units = units;
|
|
17
|
+
this.unitsStr = [];
|
|
18
|
+
this.DecimalClass = DecimalConstructor;
|
|
19
|
+
if (!units.length)
|
|
20
|
+
throw new Error('units is empty.');
|
|
21
|
+
this.threshold = option.threshold || 1;
|
|
22
|
+
this.decimal = option.fractionDigits;
|
|
23
|
+
this.highPrecision = option.useDecimal;
|
|
24
|
+
if (option.decimalOptions) {
|
|
25
|
+
this.DecimalClass = DecimalConstructor.clone(option.decimalOptions);
|
|
26
|
+
}
|
|
27
|
+
if (option.baseDigit) {
|
|
28
|
+
const us = [];
|
|
29
|
+
for (let i = 0; i < units.length; i++) {
|
|
30
|
+
this.unitsStr.push(units[i].toString());
|
|
31
|
+
us.push(units[i], option.baseDigit);
|
|
32
|
+
}
|
|
33
|
+
this.units = us.slice(0, -1);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
for (let i = 0; i < units.length; i += 2) {
|
|
37
|
+
this.unitsStr.push(units[i].toString());
|
|
38
|
+
}
|
|
39
|
+
this.units = units;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// 根据输入数值获取单位和调整后的值
|
|
43
|
+
/**
|
|
44
|
+
* Gets the appropriate unit and adjusted value for the input number
|
|
45
|
+
*
|
|
46
|
+
* @param num - The input number to determine the unit for
|
|
47
|
+
* @returns An object containing the adjusted number and its corresponding unit
|
|
48
|
+
*/
|
|
49
|
+
getUnit(num) {
|
|
50
|
+
if (!SmartUnit.ignoreNaNInputs && Number.isNaN(num))
|
|
51
|
+
throw new Error(ERROR_NAN_INPUT);
|
|
52
|
+
let i = 1;
|
|
53
|
+
if (this.highPrecision) {
|
|
54
|
+
const dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
|
|
55
|
+
const isNegative = dn.isNegative();
|
|
56
|
+
let absDn = isNegative ? dn.abs() : dn;
|
|
57
|
+
while (i < this.units.length - 1) {
|
|
58
|
+
const n = this.units[i];
|
|
59
|
+
if (typeof n === 'string')
|
|
60
|
+
throw new Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
|
|
61
|
+
if (absDn.lt(n * this.threshold)) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
absDn = absDn.dividedBy(n);
|
|
65
|
+
i += 2;
|
|
66
|
+
}
|
|
67
|
+
const result = isNegative ? absDn.neg() : absDn;
|
|
68
|
+
return {
|
|
69
|
+
num: result.toNumber(),
|
|
70
|
+
decimal: result,
|
|
71
|
+
unit: this.units[i - 1].toString(),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
if (typeof num !== 'number')
|
|
76
|
+
throw new Error(ERROR_HIGH_PRECISION_NOT_ENABLED);
|
|
77
|
+
const isNegative = num < 0;
|
|
78
|
+
let absNum = isNegative ? -num : num;
|
|
79
|
+
while (i < this.units.length - 1) {
|
|
80
|
+
const n = this.units[i];
|
|
81
|
+
if (typeof n === 'string')
|
|
82
|
+
throw new Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
|
|
83
|
+
if (absNum < n * this.threshold) {
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
absNum /= n;
|
|
87
|
+
i += 2;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
num: isNegative ? -absNum : absNum,
|
|
91
|
+
unit: this.units[i - 1].toString(),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// 将数字转换为字符串表示形式,并可选择配置小数位数
|
|
96
|
+
/**
|
|
97
|
+
* Formats a number as a string with optional decimal place configuration
|
|
98
|
+
*
|
|
99
|
+
* @param num - The number to convert to string
|
|
100
|
+
* @param decimal - Decimal precision configuration (defaults to instance setting)
|
|
101
|
+
* - If a number, defines fixed decimal places
|
|
102
|
+
* - If a string in "min-max" format, defines a range of decimal places
|
|
103
|
+
* - If omitted, uses the instance's default decimal configuration
|
|
104
|
+
* @returns The formatted string representation with unit
|
|
105
|
+
*/
|
|
106
|
+
format(num, decimal = this.decimal) {
|
|
107
|
+
const { num: n, unit, decimal: dec, } = this.getUnit(num);
|
|
108
|
+
let ns;
|
|
109
|
+
if (typeof decimal === 'number') {
|
|
110
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toFixed(decimal);
|
|
111
|
+
}
|
|
112
|
+
else if (typeof decimal === 'string') {
|
|
113
|
+
const [dp1, dp2] = decimal
|
|
114
|
+
.split('-');
|
|
115
|
+
const ndp = (n.toString().split('.')[1] || '').length;
|
|
116
|
+
const minDp = dp1 ? +dp1 : -Infinity;
|
|
117
|
+
const maxDp = dp2 ? +dp2 : Infinity;
|
|
118
|
+
if (ndp < minDp) {
|
|
119
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toFixed(minDp);
|
|
120
|
+
}
|
|
121
|
+
else if (ndp > maxDp) {
|
|
122
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toFixed(maxDp);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toString();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
ns = (dec !== null && dec !== undefined ? dec : n).toString();
|
|
130
|
+
}
|
|
131
|
+
return `${ns}${unit}`;
|
|
132
|
+
}
|
|
133
|
+
// 将给定数值从指定单位转换为基本单位
|
|
134
|
+
/**
|
|
135
|
+
* Converts a value from the specified unit to the base unit
|
|
136
|
+
*
|
|
137
|
+
* @param num - The number to convert
|
|
138
|
+
* @param unit - The original unit of the number
|
|
139
|
+
* @returns The converted value in base unit
|
|
140
|
+
* - Returns Decimal if high-precision mode is enabled
|
|
141
|
+
*/
|
|
142
|
+
toBase(num, unit) {
|
|
143
|
+
if (!SmartUnit.ignoreNaNInputs && Number.isNaN(num))
|
|
144
|
+
throw new Error(ERROR_NAN_INPUT);
|
|
145
|
+
let i = 0;
|
|
146
|
+
if (this.highPrecision) {
|
|
147
|
+
// High-precision calculation
|
|
148
|
+
let dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
|
|
149
|
+
while (i < this.units.length) {
|
|
150
|
+
if (this.units[i] === unit) {
|
|
151
|
+
return dn;
|
|
152
|
+
}
|
|
153
|
+
if (typeof this.units[i] === 'undefined') {
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
const cn = this.units[i + 1];
|
|
157
|
+
if (typeof cn !== 'number')
|
|
158
|
+
throw Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
|
|
159
|
+
dn = dn.times(cn);
|
|
160
|
+
i += 2;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
if (typeof num !== 'number')
|
|
165
|
+
throw new Error(ERROR_HIGH_PRECISION_NOT_ENABLED);
|
|
166
|
+
let nn = num;
|
|
167
|
+
// Normal calculation
|
|
168
|
+
while (i < this.units.length) {
|
|
169
|
+
if (this.units[i] === unit) {
|
|
170
|
+
return nn;
|
|
171
|
+
}
|
|
172
|
+
if (typeof this.units[i + 1] === 'undefined') {
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
if (typeof this.units[i + 1] !== 'number')
|
|
176
|
+
throw Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
|
|
177
|
+
nn *= this.units[i + 1];
|
|
178
|
+
i += 2;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
throw new Error(`Undefined unit: "${unit}".`);
|
|
182
|
+
}
|
|
183
|
+
// 从给定字符串中分离出数字部分和单位
|
|
184
|
+
/**
|
|
185
|
+
* Splits a string into its numeric part and unit
|
|
186
|
+
*
|
|
187
|
+
* @param str - Input string containing a number followed by a unit
|
|
188
|
+
* @returns An object containing the numeric value and unit
|
|
189
|
+
* Only supports predefined units
|
|
190
|
+
* Throws an error if no match is found
|
|
191
|
+
*/
|
|
192
|
+
splitUnit(str) {
|
|
193
|
+
const re = new RegExp(`^(\\d+(?:\\.\\d+)?)(${this.unitsStr.map(u => `${u}`).join('|')})`);
|
|
194
|
+
const [, num, unit] = str.match(re) || [];
|
|
195
|
+
if (num === undefined || unit === undefined) {
|
|
196
|
+
throw new Error(`Undefined unit: "${str}".`);
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
num: +num,
|
|
200
|
+
unit,
|
|
201
|
+
decimal: this.highPrecision ? new this.DecimalClass(num) : undefined,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// 将带单位的值转换为基础单位的数值
|
|
205
|
+
/**
|
|
206
|
+
* Parses a string with unit into a base unit numeric value
|
|
207
|
+
*
|
|
208
|
+
* @param str - Input string containing a number and unit
|
|
209
|
+
* @returns The value converted to base unit
|
|
210
|
+
* - Returns Decimal if high-precision mode is enabled
|
|
211
|
+
*/
|
|
212
|
+
parse(str) {
|
|
213
|
+
const { num, unit, decimal, } = this.splitUnit(str);
|
|
214
|
+
return this.toBase((decimal !== null && decimal !== undefined ? decimal : num), unit);
|
|
215
|
+
}
|
|
216
|
+
// 将给定数值从原单位转换为最佳单位,并可指定小数精度
|
|
217
|
+
/**
|
|
218
|
+
* Converts a value from the original unit to the optimal unit with optional decimal precision
|
|
219
|
+
*
|
|
220
|
+
* @param num - The number to convert
|
|
221
|
+
* @param unit - The original unit
|
|
222
|
+
* @param decimal - Optional decimal places for formatting output
|
|
223
|
+
* @returns The converted number as a formatted string
|
|
224
|
+
*/
|
|
225
|
+
fromUnitFormat(num, unit, decimal) {
|
|
226
|
+
const nnum = this.toBase(num, unit);
|
|
227
|
+
return this.format(nnum, decimal);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
SmartUnit.ignoreNaNInputs = false;
|
|
231
|
+
|
|
232
|
+
exports.ERROR_HIGH_PRECISION_NOT_ENABLED = ERROR_HIGH_PRECISION_NOT_ENABLED;
|
|
233
|
+
exports.ERROR_NAN_INPUT = ERROR_NAN_INPUT;
|
|
234
|
+
exports.SmartUnit = SmartUnit;
|
|
235
|
+
exports.default = SmartUnit;
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "smart-unit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"repository": "https://github.com/flycran/smart-unit.git",
|
|
9
|
+
"homepage": "https://github.com/flycran/smart-unit",
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@biomejs/biome": "2.4.7",
|
|
12
|
+
"@rollup/plugin-commonjs": "^28.0.3",
|
|
13
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
14
|
+
"@rollup/plugin-typescript": "^12.1.2",
|
|
15
|
+
"rollup": "~4.30.1",
|
|
16
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
17
|
+
"terser": "^5.39.0",
|
|
18
|
+
"ts-node": "^10.9.1",
|
|
19
|
+
"tslib": "^2.8.1",
|
|
20
|
+
"typescript": "^5.8.3",
|
|
21
|
+
"vitest": "^4.1.0"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md",
|
|
26
|
+
"README.zh-CN.md"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "rollup -c --configPlugin typescript",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:watch": "vitest"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"Automatically select the appropriate unit of measurement"
|
|
35
|
+
],
|
|
36
|
+
"author": "Flycran",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"decimal.js": "^10.5.0"
|
|
40
|
+
}
|
|
41
|
+
}
|