- 后端
【免费下载链接】bignumber.js
A JavaScript library for arbitrary-precision decimal and non-decimal arithmetic
本指南完整讲解 bignumber.js 仓库perf目录下三个遗留(legacy)但依然可用的对比测试工具:命令行程序bigtime.js与bigtime-OOM.js,以及浏览器页面bignumber-vs-bigdecimal.html。它们能在大量随机输入上同时运行 bignumber.js 的方法与两个 JavaScript 版 BigDecimal(GWT 移植与 ICU4J 移植)的对应方法,逐一核对结果是否一致并统计耗时,适合做正确性交叉验证与性能基准。读完本文,你将掌握这三个工具的参数语义、默认值、底层执行流程与结果校验原理,并能用它们复现 GWT BigDecimal 移植中的已知缺陷。
perf 目录的定位:旧工具、新用途
perf目录(见 perf/README.md)中存放的是项目作者早期编写的一批对比测试程序。它们虽然年代较早,但在当前仓库中依然可以运行,其价值在于:在大量随机输入上交叉验证 bignumber.js 的计算结果。这也是仓库主 README.md 的 "Test" 一节中明确提到的用法——"还有一些位于perf的旧程序仍然可用,可用于在大量随机输入上测试与交叉核对结果"。
目录结构如下:
- perf/bigtime.js —— Node.js 命令行对比计时工具(推荐使用);
- perf/bigtime-OOM.js —— 同样用途,但额外输出对象创建与方法调用的分段时间,代价是有内存溢出风险;
- perf/bignumber-vs-bigdecimal.html —— 浏览器中的可视化对比页面;
- perf/lib/bigdecimal_GWT/ —— GWT 移植的
java.math.BigDecimal; - perf/lib/bigdecimal_ICU4J/ —— ICU4J 移植的
com.ibm.icu.math.BigDecimal。
两个命令行工具通过require('..')直接加载仓库根目录的 bignumber.js 入口(perf/bigtime.js),再require各自lib目录下的 BigDecimal 移植版本,因此无需安装任何 npm 依赖即可运行(唯一前提是仓库根目录的bignumber.js文件存在,它本身是单文件源码)。
bigtime.js:命令行对比计时的首选
基本用法
在仓库根目录执行:
node perf/bigtime plus 10000 40这条命令的含义是:对 bignumber.js 的plus方法与 GWT BigDecimal 的add方法各计时 10000 次调用,操作数使用最多 40 位的随机数字,并逐一检查两边结果是否一致。执行结束后会输出如下信息:方法名、调用次数、随机操作数个数、最大位数、BigDecimal 与 BigNumber 各自的总耗时,以及"谁快多少倍"的结论(若两边耗时差不超过 2 毫秒则显示 "Times approximately equal")。
查看完整帮助:
node perf/bigtime -h帮助文本由脚本自身在参数无法识别时打印(见 perf/bigtime.js),其中给出了完整参数语法与默认值说明。
参数语义与默认值
命令行语法为:
node bigtime [METHOD] [METHOD CALLS [MAX DIGITS [DECIMAL PLACES]]]各位置参数(从 perf/bigtime.js 的参数解析逻辑可确认):
| 位置 | 参数 | 说明 | 默认值 |
|---|---|---|---|
| 1 | METHOD | 要计时并对比的方法名(见下方映射表) | 随机选择 |
| 2 | METHOD CALLS | 每个实现的方法调用次数 | 10000(pow为 100) |
| 3 | MAX DIGITS | 随机操作数的最大位数 | 20(pow为 20) |
| 4 | DECIMAL PLACES | 除法使用的小数位数 | 20 |
对应的常量定义在 perf/bigtime.js:DEFAULT_REPS = 1e4、DEFAULT_POW_REPS = 1e2、DEFAULT_MAX_DIGITS = 20、DEFAULT_POW_MAX_DIGITS = 20、DEFAULT_PLACES = 20。脚本还会校验数值上限:调用次数超过1e10、位数超过1e6时按非法值处理。
帮助中给出的典型示例包括:
node bigtime # 完全随机 node bigtime minus # 指定方法 node bigtime add 100000 # 10 万次调用 node bigtime times 20000 100 node bigtime div 100000 50 20 node bigtime 9000 # 只给次数 node bigtime 1000000 20 node bigtime m add # 附加内存统计附带参数m或-m可开启内存变化统计(rss、heapUsed、heapTotal,单位 KB)。
方法映射表
脚本内部维护了三张方法名数组(perf/bigtime.js),将 BigDecimal 方法与 bignumber.js 方法一一对应:
| BigDecimal(GWT 移植) | bignumber.js | 说明 |
|---|---|---|
add | plus | 加法 |
subtract | minus | 减法 |
multiply | multipliedBy(别名times) | 乘法 |
divide | dividedBy(别名div) | 除法 |
remainder | modulo(别名mod) | 取模 |
compareTo | comparedTo | 比较 |
pow | exponentiatedBy(别名pow) | 幂 |
negate | negated | 取负 |
abs | absoluteValue | 绝对值 |
命令行参数 METHOD 优先从 bignumber.js 一侧识别(plus、minus、dividedBy、div、mod等),脚本会自动匹配对应的 BigDecimal 方法名(perf/bigtime.js)。注意:bigtime.js同时支持一元方法(abs、negate,只需一个操作数),这是它与bigtime-OOM.js的一个重要差异。
执行流程:分批生成、分批计时、逐批校验
从源码结构看,bigtime.js的核心执行流程(perf/bigtime.js)分为四步:
- 分批处理:外层循环
for (; reps > 0; reps -= 1e4)将总调用次数切分为每批最多 1 万个(j = Math.min(reps, 1e4))。这是它能"不容易耗尽内存"的根本原因——随机数数组与结果数组每批只保留 1 万个元素,随用随弃。 - 生成随机操作数:
getRandom(maxDigits)(perf/bigtime.js)生成普通记法的随机数字字符串——位数在 1 到maxDigits之间随机,约 20% 概率为整数,50% 概率为负数;若目标是divide/remainder且随机到 0,会强制替换为非零数字以避免除零错误。pow的第二个操作数是 0~50 的随机整数指数(MAX_POWER = 50)。README 中记载该工具以指数记法生成随机数,不过当前源码中启用的生成器为普通记法,指数记法版本以注释形式保留在 perf/bigtime.js。 - 分别计时:先对 BigDecimal 侧计时(
bdT),再对 BigNumber 侧计时(bnT),每批累加到bdTotal/bnTotal;若开启了m参数,每段前后调用getMemory统计内存增量(perf/bigtime.js)。 - 逐结果校验:将
bnRs[i].toString()与bdRs[i].toPlainString()做字符串比较;BigDecimal 的非整数结果会先用正则/\.?0+$/去掉尾部零再比较(perf/bigtime.js)。一旦发现首个不一致,立即打印双方结果与操作数(除法场景还会附上dp与rounding)并终止。
全部通过则汇总耗时,调用getFastest(perf/bigtime.js)给出结论:只有当两边总耗时之差大于 2 毫秒时才判定快慢,并输出倍数(保留 1 位小数);否则输出 "Times approximately equal"。
脚本内预设的 BigNumber 配置
两个命令行工具在执行前都会通过BigNumber.config设置一组对比友好的配置(perf/bigtime.js):
BigNumber.config({ EXPONENTIAL_AT: 1E9, // 超过该阈值才使用指数记法输出,避免结果被科学计数法干扰比对 RANGE: 1E9, // 扩大可表示数值的指数范围 ERRORS: false, // 早期版本配置项(控制错误抛出),属于历史遗留设置 MODULO_MODE: 1, // 等于 BigNumber.EUCLID,使用欧几里得模 POW_PRECISION: 10000 // pow 结果的小数位数上限 });其中EXPONENTIAL_AT: 1e9、RANGE: 1e9与 doc/API.html 中记载的默认值EXPONENTIAL_AT: [-10, 20]、RANGE: 1e+9(见 doc/API.html)不同,是为了让所有操作数以普通十进制字符串输出、便于与 BigDecimal 结果比对。此外,当被测方法为divide时,脚本会随机选取一个舍入模式(Math.floor(Math.random() * 7),对应 0~6)并同步设置DECIMAL_PLACES与ROUNDING_MODE(perf/bigtime.js),使两边在相同舍入条件下对齐结果。
bigtime-OOM.js:分项计时版,但小心内存
bigtime-OOM.js与bigtime.js参数语法一致(node perf/bigtime-OOM [METHOD] [METHOD CALLS [MAX DIGITS [DECIMAL PLACES]]]),差异在于它把"对象创建"与"方法调用"分开计时,并额外计算操作数的平均位数。
与 bigtime.js 的完整对比
perf/README.md 的 "Further notes" 部分给出了两份工具的详细差异,整理如下:
| 维度 | bigtime.js | bigtime-OOM.js |
|---|---|---|
| 随机数与对象的创建方式 | 分批(每批最多 1 万个)创建 | 一次性全部创建 |
| 内存风险 | 基本不会耗尽内存 | 可能内存溢出,例如iterations > 500000且random digits > 40时 |
| 计时粒度 | 不分对象创建与方法调用 | 分别输出对象创建耗时与方法调用耗时 |
| 被测方法 | 一元与二元方法均覆盖(含abs、negate) | 仅二元方法(无abs、negate) |
| 随机数生成进度 | 不提示完成情况 | 打印"Creating N random numbers... done" |
| 平均位数统计 | 无 | 计算并打印操作数平均位数 |
| 随机数记法 | README 记载为指数记法(当前源码为普通记法) | 普通记法 |
执行流程与输出格式
bigtime-OOM.js的流程(perf/bigtime-OOM.js)是:先生成全部随机数 → 计时创建 BigDecimals → 计时创建 BigNumbers → 计时双方方法调用 → 输出分项结论 → 统一校验结果。
输出示例结构:
BigNumber plus vs BigDecimal add Method calls: 10000 Creating 20000 random numbers (max. digits: 20)... done Average number of digits: 10 Creating BigDecimals... done. Time taken: 123 ms Creating BigNumbers... done. Time taken: 45 ms Object creation: BigNumber was 2.7 times faster BigDecimal add... done. Time taken: 456 ms BigNumber plus... done. Time taken: 89 ms Method calls: BigNumber was 5.1 times faster Overall: BigNumber was 4.8 times faster Checking for mismatches... done. None found.内存统计通过process.memoryUsage()的rss、heapUsed、heapTotal差值计算(perf/bigtime-OOM.js),同样需要m参数开启。
内存溢出的触发条件
README 明确指出:当iterations > 500000且random digits > 40时,bigtime-OOM.js可能耗尽内存。原因是它将reps个操作数与结果全部保存在数组中(perf/bigtime-OOM.js),数字越大、位数越长,占用内存越多。相比之下bigtime.js采用reps -= 1e4的分批策略(perf/bigtime.js),因此被 README 推荐为常规选择。
浏览器版本:bignumber-vs-bigdecimal.html
在浏览器中打开 perf/bignumber-vs-bigdecimal.html 即可使用可视化对比页面。页面加载了两个脚本(perf/bignumber-vs-bigdecimal.html):
<script src='../dist/bignumber.js'></script> <script src='./lib/bigdecimal_GWT/bigdecimal.js'></script>注意:它引用的是构建产物dist/bignumber.js,因此使用前需要先在仓库根目录执行npm run build(或node build.js)生成dist目录,详见 README.md 的 Build 一节。ICU4J 版本则是页面运行时通过动态插入<script>按需加载(perf/bignumber-vs-bigdecimal.html)。
界面操作说明
页面整体"自解释"(README 原话),核心控件包括:
- 方法单选按钮(perf/bignumber-vs-bigdecimal.html):
plus/minus/multipliedBy/dividedBy/modulo/comparedTo/absoluteValue/negated/exponentiatedBy,对应 BigDecimal 的add/subtract/multiply/divide/remainder/compareTo/abs/negate/pow; - BigDecimal 版本:GWT 或 ICU4J 单选;当 GWT 且勾选 "Integers only" 时,右侧标注会切换为
BigInteger(此时使用 GWT 移植一并导出的java.math.BigInteger); - 随机数位数:
Random number digits输入框,配合Fixed(固定位数)/Max(最大位数)单选,以及 "Integers only" 复选框; - 除法专属选项:选择
dividedBy时出现Decimal places输入框与Rounding下拉(UP / DOWN / CEIL / FLOOR / HALF_UP / HALF_DOWN / HALF_EVEN,对应舍入模式 0~6); - Iterations:迭代次数输入框;勾选 "Show all (no timing)" 则关闭计时、逐条展示每次运算的输入与输出;
- Start 按钮:开始/重启测试;再次点击任意方法单选按钮可立即停止;按空格键暂停/继续(事件绑定见 perf/bignumber-vs-bigdecimal.html)。
页面默认值(perf/bignumber-vs-bigdecimal.html):迭代 10000 次、随机数最多 20 位、除法小数位 20、舍入模式 4(HALF_UP)、默认选中 GWT 与 Max。页面同样预先配置了DECIMAL_PLACES: 20、ROUNDING_MODE: 4、EXPONENTIAL_AT: 1e9、RANGE: 1e9、MODULO_MODE: 1、POW_PRECISION: 10000(perf/bignumber-vs-bigdecimal.html)。
两个移植版本的 API 差异(页面源码注释)
页面末尾的源码注释(perf/bignumber-vs-bigdecimal.html)记录了开发者实测得出的两版差异:
- ICU4J(IBM
com.ibm.icu.math包):pow的参数必须是 BigDecimal 类型;没有toPlainString()与stripTrailingZeros();只导出BigDecimal。页面注释中的经验记录是:在 Firefox 上远快于 GWT 版,在 Chrome 上则随方法而异; - GWT(Java 标准类库
java.math.BigDecimal):导出RoundingMode、MathContext、BigDecimal、BigInteger;pow的参数必须是 number 类型;提供toPlainString、stripTrailingZeros等方法。
正因如此,页面在比对结果时对两种版本采用不同的规范化策略(perf/bignumber-vs-bigdecimal.html):GWT 版用stripTrailingZeros().toPlainString(),ICU4J 版用toString()后正则剔除尾部零。命令行工具则统一使用toPlainString()加正则处理(GWT 版提供该方法)。
BigInteger 模式的限制
勾选 "Integers only" 且选择 GWT 时,对比对象切换为BigInteger,此时页面会自动禁用dividedBy单选按钮并切回plus(perf/bignumber-vs-bigdecimal.html)。原因在注释中说明:BigInteger在除法"无法得到精确可表示的小数结果"时会抛出异常,因此无法参与除法对比。
交叉验证的价值:GWT BigDecimal 移植的已知缺陷
README 特别提醒:npm registry 中的 BigDecimal 包就是 GWT 版本,它存在若干缺陷。具体缺陷示例集中写在 perf/lib/bigdecimal_GWT/bugs.js 中(运行方式为node perf/lib/bigdecimal_GWT/bugs),涉及remainder、divide、compareTo三个方法:
| 方法 | 输入 | GWT 实际输出 | 正确结果 |
|---|---|---|---|
remainder | 9.785496E-2对-5.9219189762E-2 | 0.09785496 | 0.038635770238 |
remainder | 1.23693014661017964112E-5对-6.9318042E-7 | 0.0000123693014661017964112 | 0.0000005852343261017964112 |
divide(40 位,ROUND_HALF_EVEN) | 6.9609119610E-78 ÷ 4E-48 | 1.7402279903E-30 | 1.7402279902E-30 |
divide(40 位,ROUND_HALF_EVEN) | 5.383458817E-83 ÷ 8E-54 | 6.7293235213E-30 | 6.7293235212E-30 |
compareTo | 0.04与0.079393068 | 1 | -1 |
compareTo | 7.88749578569876987785987658649E-10与4.2545098709E-6 | 1 | -1 |
这些"正确结果"的权威来源是同一目录下的 Java 程序 perf/lib/bigdecimal_GWT/BigDecTest.java(用javac BigDecTest.java && java BigDecTest编译运行,输出即注释中的预期值)。它使用的正是 Java 标准库java.math.BigDecimal,可作为 GWT JavaScript 移植版的参照基准——这也解释了为什么交叉验证需要同时准备 GWT 与 ICU4J 两个移植版本:它们各自独立移植自不同来源,彼此结果相互印证,任何一方与 bignumber.js 结果不一致都值得深究。
结果一致性校验的原理
三个工具共享同一套结果比对思想:BigDecimal 结果规范化后与 BigNumber 的toString()逐字符比较。规范化规则(见 perf/bigtime.js):
- 取 BigDecimal 的
toPlainString()(ICU4J 版退化为toString()); - 若含小数点,用正则
\.?0+$剥掉尾部零(例如"0.500"→"0.5"); - 与
bnRs[i].toString()严格相等才视为通过。
任何一侧结果不一致都会打印首个失配样本的完整上下文——操作数、方法、结果、除法参数(dp、rounding)——方便直接复现。这正是这套工具作为"大规模随机输入的交叉核对"手段的核心价值:普通单元测试覆盖不到的边界组合,可以通过海量随机样本暴露出来。
使用建议与注意事项
- 优先使用
bigtime.js:README 明确推荐它,原因是内存占用可控(分批执行)、覆盖一元与二元方法;bigtime-OOM.js仅在需要区分"对象创建"与"方法调用"耗时、且输入规模可控(避开iterations > 500000且digits > 40的组合)时使用。 - 浏览器页面需先构建:它引用
dist/bignumber.js,请先执行npm run build再打开 perf/bignumber-vs-bigdecimal.html。 - 对比前先确认配置对齐:除法对比时舍入模式由脚本随机选取(0~6),
DECIMAL_PLACES通过命令行第 4 个参数指定;脚本内部已将EXPONENTIAL_AT、RANGE、MODULO_MODE、POW_PRECISION预设为对比友好值(详见 doc/API.html 中各配置项的定义)。 - 结果不一致不等于 bignumber.js 出错:如上一节所示,GWT 移植本身存在
remainder、divide、compareTo缺陷,遇到失配时应先对照 perf/lib/bigdecimal_GWT/BigDecTest.java 与 ICU4J 版本确认基准的正确性。
- 后端
【免费下载链接】bignumber.js
A JavaScript library for arbitrary-precision decimal and non-decimal arithmetic
相关推荐
VRCX虚拟社交中枢系统:3大核心技术架构解析与高性能部署指南
VRCX虚拟社交中枢系统:3大核心技术架构解析与高性能部署指南 VRCX作为一款基于VRChat官方API开发的高级虚拟社交中枢系统,通过智能定位系统与好友关系
桌面应用SGLang DeepSeek 内核基准测试指南:DeepGemm FP8 GEMM 性能对比与正确性验证
SGLang DeepSeek 内核基准测试指南:DeepGemm FP8 GEMM 性能对比与正确性验证 本指南以 benchmark/kernels/dee
模型推理服务推理引擎人工智能大模型本地部署多模态autocannon配置验证工具:确保性能测试场景的正确性
autocannon配置验证工具:确保性能测试场景的正确性 在高并发HTTP性能测试中,错误的配置参数可能导致测试结果失真或系统过载。autocannon作为N
性能测试测试开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考