From 8848f299583f38622196c039d04eb8f0b01ce528 Mon Sep 17 00:00:00 2001 From: Luke Steyn Date: Tue, 17 Jun 2025 19:29:40 +0800 Subject: [PATCH 1/5] Test base --- sdk/package.json | 1 + sdk/tests/bn/performance.test.ts | 130 +++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 sdk/tests/bn/performance.test.ts diff --git a/sdk/package.json b/sdk/package.json index 2d8d303855..ab61c799cb 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -18,6 +18,7 @@ "test": "mocha -r ts-node/register tests/**/*.ts", "test:inspect": "mocha --inspect-brk -r ts-node/register tests/**/*.ts", "test:bignum": "mocha -r ts-node/register tests/bn/**/*.ts", + "test:bignum-perf": "mocha -r ts-node/register tests/bn/performance.test.ts", "test:ci": "mocha -r ts-node/register tests/ci/**/*.ts", "patch-and-pub": "npm version patch --force && npm publish", "prettify": "prettier --check './src/***/*.ts'", diff --git a/sdk/tests/bn/performance.test.ts b/sdk/tests/bn/performance.test.ts new file mode 100644 index 0000000000..db27348da2 --- /dev/null +++ b/sdk/tests/bn/performance.test.ts @@ -0,0 +1,130 @@ +import { BN } from '../../src/index'; +import { BigNum } from '../../src/factory/bigNum'; + +const BIGNUM_VERSION = 'v1.0'; + +describe('BigNum Performance Tests', () => { + const testValues = [ + { val: '123', precision: 0 }, + { val: '1234567', precision: 0 }, + { val: '123456789', precision: 3 }, + { val: '1000000000123', precision: 6 }, + { val: '999999999999999', precision: 9 }, + { val: '123456789012345', precision: 12 }, + ]; + + const createTestBigNums = () => { + return testValues.map(({ val, precision }) => + BigNum.from(new BN(val), new BN(precision)) + ); + }; + + const performanceTest = (name: string, fn: () => void, iterations: number) => { + const start = performance.now(); + for (let i = 0; i < iterations; i++) { + fn(); + } + const end = performance.now(); + const duration = end - start; + console.log(`[${BIGNUM_VERSION}] ${name}: ${duration.toFixed(2)}ms (${iterations} iterations)`); + return duration; + }; + + it('should benchmark print() method', () => { + const bigNums = createTestBigNums(); + + performanceTest('print() method', () => { + bigNums.forEach(bn => bn.print()); + }, 100000); + }); + + it('should benchmark prettyPrint() method', () => { + const bigNums = createTestBigNums(); + + performanceTest('prettyPrint() method', () => { + bigNums.forEach(bn => bn.prettyPrint()); + }, 100000); + }); + + it('should benchmark toFixed() method', () => { + const bigNums = createTestBigNums(); + + performanceTest('toFixed() method', () => { + bigNums.forEach(bn => bn.toFixed(4)); + }, 100000); + }); + + it('should benchmark toNum() method', () => { + const bigNums = createTestBigNums(); + + performanceTest('toNum() method', () => { + bigNums.forEach(bn => bn.toNum()); + }, 100000); + }); + + it('should benchmark printShort() method', () => { + const bigNums = createTestBigNums(); + + performanceTest('printShort() method', () => { + bigNums.forEach(bn => bn.printShort()); + }, 100000); + }); + + it('should stress test with large numbers', () => { + const largeBigNums = [ + BigNum.from(new BN('999999999999999999999999999999'), new BN(15)), + BigNum.from(new BN('123456789012345678901234567890'), new BN(18)), + BigNum.from(new BN('987654321098765432109876543210'), new BN(20)), + ]; + + performanceTest('Large number print()', () => { + largeBigNums.forEach(bn => bn.print()); + }, 50000); + + performanceTest('Large number prettyPrint()', () => { + largeBigNums.forEach(bn => bn.prettyPrint()); + }, 50000); + + performanceTest('Large number toFixed()', () => { + largeBigNums.forEach(bn => bn.toFixed(4)); + }, 50000); + }); + + it('should test repeated operations on single instance', () => { + const bigNum = BigNum.from(new BN('123456789'), new BN(6)); + + performanceTest('Repeated print() operations', () => { + for (let i = 0; i < 1000; i++) { + bigNum.print(); + } + }, 1000); + + performanceTest('Repeated prettyPrint() operations', () => { + for (let i = 0; i < 1000; i++) { + bigNum.prettyPrint(); + } + }, 1000); + + performanceTest('Repeated toFixed() operations', () => { + for (let i = 0; i < 1000; i++) { + bigNum.toFixed(2); + } + }, 1000); + }); + + it('should benchmark locale-specific formatting', () => { + const bigNums = createTestBigNums(); + + performanceTest('toNum() with default locale', () => { + bigNums.forEach(bn => bn.toNum()); + }, 100000); + + BigNum.setLocale('de-DE'); + + performanceTest('toNum() with custom locale', () => { + bigNums.forEach(bn => bn.toNum()); + }, 100000); + + BigNum.setLocale('en-US'); + }); +}); \ No newline at end of file From 7d086f1804ffab91a21584947937861b51d2d239 Mon Sep 17 00:00:00 2001 From: Luke Steyn Date: Tue, 17 Jun 2025 19:32:13 +0800 Subject: [PATCH 2/5] 1.1 improvements --- sdk/src/factory/bigNum.ts | 84 +++++++++++++++++++------------- sdk/tests/bn/performance.test.ts | 2 +- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/sdk/src/factory/bigNum.ts b/sdk/src/factory/bigNum.ts index f74de0692b..c99b1855e5 100644 --- a/sdk/src/factory/bigNum.ts +++ b/sdk/src/factory/bigNum.ts @@ -252,28 +252,39 @@ export class BigNum { useTradePrecision?: boolean, precisionOverride?: number ): string { - const [leftSide, rightSide] = this.printShort( - useTradePrecision, - precisionOverride - ).split(BigNum.delim); - - let formattedLeftSide = leftSide; + const printVal = this.printShort(useTradePrecision, precisionOverride); + const delimIndex = printVal.indexOf(BigNum.delim); + + let leftSide: string; + let rightSide: string; + + if (delimIndex === -1) { + leftSide = printVal; + rightSide = ''; + } else { + leftSide = printVal.substring(0, delimIndex); + rightSide = printVal.substring(delimIndex + 1); + } - const isNeg = formattedLeftSide.includes('-'); + const isNeg = leftSide.startsWith('-'); if (isNeg) { - formattedLeftSide = formattedLeftSide.replace('-', ''); + leftSide = leftSide.substring(1); } - let index = formattedLeftSide.length - 3; - - while (index >= 1) { - const formattedLeftSideArray = formattedLeftSide.split(''); - - formattedLeftSideArray.splice(index, 0, BigNum.spacer); - - formattedLeftSide = formattedLeftSideArray.join(''); + if (leftSide.length <= 3) { + return `${isNeg ? '-' : ''}${leftSide}${ + rightSide ? `${BigNum.delim}${rightSide}` : '' + }`; + } - index -= 3; + let formattedLeftSide = ''; + const len = leftSide.length; + + for (let i = 0; i < len; i++) { + if (i > 0 && (len - i) % 3 === 0) { + formattedLeftSide += BigNum.spacer; + } + formattedLeftSide += leftSide[i]; } return `${isNeg ? '-' : ''}${formattedLeftSide}${ @@ -317,15 +328,24 @@ export class BigNum { } const printString = this.print(); + const delimIndex = printString.indexOf(BigNum.delim); + + let leftSide: string; + let rightSide: string; + + if (delimIndex === -1) { + leftSide = printString; + rightSide = ''; + } else { + leftSide = printString.substring(0, delimIndex); + rightSide = printString.substring(delimIndex + 1); + } - const [leftSide, rightSide] = printString.split(BigNum.delim); - - const filledRightSide = [ - ...(rightSide ?? '').slice(0, fixedPrecision), - ...Array(fixedPrecision).fill('0'), - ] - .slice(0, fixedPrecision) - .join(''); + const truncatedRightSide = rightSide.length > fixedPrecision + ? rightSide.substring(0, fixedPrecision) + : rightSide; + + const filledRightSide = truncatedRightSide.padEnd(fixedPrecision, '0'); return `${leftSide}${BigNum.delim}${filledRightSide}`; } @@ -613,14 +633,12 @@ export class BigNum { // Must convert any non-US delimiters and spacers to US format before using parseFloat if (BigNum.delim !== '.' || BigNum.spacer !== ',') { - printedValue = printedValue - .split('') - .map((char) => { - if (char === BigNum.delim) return '.'; - if (char === BigNum.spacer) return ','; - return char; - }) - .join(''); + if (BigNum.delim !== '.') { + printedValue = printedValue.replace(new RegExp('\\' + BigNum.delim, 'g'), '.'); + } + if (BigNum.spacer !== ',') { + printedValue = printedValue.replace(new RegExp('\\' + BigNum.spacer, 'g'), ','); + } } return parseFloat(printedValue); diff --git a/sdk/tests/bn/performance.test.ts b/sdk/tests/bn/performance.test.ts index db27348da2..194364281e 100644 --- a/sdk/tests/bn/performance.test.ts +++ b/sdk/tests/bn/performance.test.ts @@ -1,7 +1,7 @@ import { BN } from '../../src/index'; import { BigNum } from '../../src/factory/bigNum'; -const BIGNUM_VERSION = 'v1.0'; +const BIGNUM_VERSION = 'v1.1'; describe('BigNum Performance Tests', () => { const testValues = [ From a1e1de234a306f418bd74fb573f56f74d533d6b2 Mon Sep 17 00:00:00 2001 From: Luke Steyn Date: Tue, 17 Jun 2025 19:37:11 +0800 Subject: [PATCH 3/5] v1.2 improvement --- sdk/src/factory/bigNum.ts | 7 ++----- sdk/tests/bn/performance.test.ts | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sdk/src/factory/bigNum.ts b/sdk/src/factory/bigNum.ts index c99b1855e5..68b86d3ebc 100644 --- a/sdk/src/factory/bigNum.ts +++ b/sdk/src/factory/bigNum.ts @@ -221,10 +221,7 @@ export class BigNum { const precisionNum = this.precision.toNumber(); // make a string with at least the precisionNum number of zeroes - let printString = [ - ...Array(this.precision.toNumber()).fill(0), - ...plainString.split(''), - ].join(''); + let printString = '0'.repeat(precisionNum) + plainString; // inject decimal printString = @@ -233,7 +230,7 @@ export class BigNum { printString.substring(printString.length - precisionNum); // remove leading zeroes - printString = printString.replace(/^0+/, ''); + printString = printString.replace(/^0+(?=\d)/, '') || '0'; // add zero if leading delim if (printString[0] === BigNum.delim) printString = `0${printString}`; diff --git a/sdk/tests/bn/performance.test.ts b/sdk/tests/bn/performance.test.ts index 194364281e..0ad5f3c5bd 100644 --- a/sdk/tests/bn/performance.test.ts +++ b/sdk/tests/bn/performance.test.ts @@ -1,7 +1,7 @@ import { BN } from '../../src/index'; import { BigNum } from '../../src/factory/bigNum'; -const BIGNUM_VERSION = 'v1.1'; +const BIGNUM_VERSION = 'v1.2'; describe('BigNum Performance Tests', () => { const testValues = [ From f8f30688ee41c99f525af82dcf8d62265a15e355 Mon Sep 17 00:00:00 2001 From: Luke Steyn Date: Tue, 17 Jun 2025 19:44:36 +0800 Subject: [PATCH 4/5] v1.3 improvements --- sdk/src/factory/bigNum.ts | 40 ++++++++++++++++++-------------- sdk/tests/bn/performance.test.ts | 2 +- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/sdk/src/factory/bigNum.ts b/sdk/src/factory/bigNum.ts index 68b86d3ebc..1966cd452a 100644 --- a/sdk/src/factory/bigNum.ts +++ b/sdk/src/factory/bigNum.ts @@ -216,33 +216,37 @@ export class BigNum { 'Tried to print a BN with precision lower than zero' ); - const isNeg = this.isNeg(); - const plainString = this.abs().toString(); const precisionNum = this.precision.toNumber(); + + // Early return for zero precision + if (precisionNum === 0) { + return this.val.toString(); + } + + const isNeg = this.val.isNeg(); + const plainString = this.val.abs().toString(); - // make a string with at least the precisionNum number of zeroes + // Build padded string with leading zeros let printString = '0'.repeat(precisionNum) + plainString; - // inject decimal - printString = - printString.substring(0, printString.length - precisionNum) + - BigNum.delim + - printString.substring(printString.length - precisionNum); + // Insert decimal point + const insertPos = printString.length - precisionNum; + printString = printString.substring(0, insertPos) + BigNum.delim + printString.substring(insertPos); - // remove leading zeroes + // Remove leading zeros but keep at least one digit before decimal printString = printString.replace(/^0+(?=\d)/, '') || '0'; - // add zero if leading delim - if (printString[0] === BigNum.delim) printString = `0${printString}`; - - // Add minus if negative - if (isNeg) printString = `-${printString}`; + // Handle case where we have leading decimal after zero removal + if (printString[0] === BigNum.delim) { + printString = '0' + printString; + } - // remove trailing delim - if (printString[printString.length - 1] === BigNum.delim) - printString = printString.slice(0, printString.length - 1); + // Remove trailing decimal if present + if (printString.endsWith(BigNum.delim)) { + printString = printString.slice(0, -1); + } - return printString; + return isNeg ? `-${printString}` : printString; } public prettyPrint( diff --git a/sdk/tests/bn/performance.test.ts b/sdk/tests/bn/performance.test.ts index 0ad5f3c5bd..e7269216ac 100644 --- a/sdk/tests/bn/performance.test.ts +++ b/sdk/tests/bn/performance.test.ts @@ -1,7 +1,7 @@ import { BN } from '../../src/index'; import { BigNum } from '../../src/factory/bigNum'; -const BIGNUM_VERSION = 'v1.2'; +const BIGNUM_VERSION = 'v1.3'; describe('BigNum Performance Tests', () => { const testValues = [ From c28927c222803a91f6f833a7c909d0ddf06b29ae Mon Sep 17 00:00:00 2001 From: Luke Steyn Date: Tue, 17 Jun 2025 19:56:58 +0800 Subject: [PATCH 5/5] Bump --- sdk/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/package.json b/sdk/package.json index ab61c799cb..4fc02b294c 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -17,7 +17,7 @@ "clean": "rm -rf lib", "test": "mocha -r ts-node/register tests/**/*.ts", "test:inspect": "mocha --inspect-brk -r ts-node/register tests/**/*.ts", - "test:bignum": "mocha -r ts-node/register tests/bn/**/*.ts", + "test:bignum": "mocha -r ts-node/register tests/bn/test.ts", "test:bignum-perf": "mocha -r ts-node/register tests/bn/performance.test.ts", "test:ci": "mocha -r ts-node/register tests/ci/**/*.ts", "patch-and-pub": "npm version patch --force && npm publish",