From 0520e78ae9487a2d74b77fe23adb6b8b0c0e6128 Mon Sep 17 00:00:00 2001 From: alan890104 Date: Sun, 10 Dec 2023 23:04:39 +0800 Subject: [PATCH 1/4] feat: Add sqrt method for float * feat(math_example.tact): add support for calculating square root of a fixed point float * feat(float.fc): implement sqrtFloat function to calculate the square root of a fixed point float * test(float.spec.ts): add tests for calculating square root of a fixed point float --- contracts/math_example.tact | 7 +++++ contracts/packages/math/float.fc | 13 +++++++++ tests/math/float.spec.ts | 48 ++++++++++++++++++++++++++++---- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/contracts/math_example.tact b/contracts/math_example.tact index ed01511..7c64e02 100644 --- a/contracts/math_example.tact +++ b/contracts/math_example.tact @@ -28,6 +28,9 @@ extends native mul(self: Int, b: Int): Int; @name(div) extends native div(self: Int, b: Int): Int; +@name(sqrtFloat) +extends native sqrtFloat(self: Int): Int; + message Arithmetic { floatA: Int; floatB: Int; @@ -57,6 +60,10 @@ contract MathExample with Deployable { self.result = msg.floatA.safeDiv(msg.floatB); return ; } + if (msg.op == 4) { + self.result = msg.floatA.sqrtFloat(); + return ; + } } get fun float(value: Int): Int { diff --git a/contracts/packages/math/float.fc b/contracts/packages/math/float.fc index f7a3eb3..6387838 100644 --- a/contracts/packages/math/float.fc +++ b/contracts/packages/math/float.fc @@ -80,3 +80,16 @@ int safeDiv(int floatA, int floatB) inline_ref { return (floatA << 64) / floatB; } +;; sqrtFloat function is used to calculate the square root of a fixed point float +;; used newton's method to approximate the square root, since the precision is 64 bit, we need to shift 32 bit back +int sqrtFloat(int x) inline_ref { + int z = (x + 1) / 2; + int y = x; + while (z < y) { + y = z; + z = (x / z + z) / 2; + } + ;; y << (self.precision // 2) + ;; The precision of fixed point float is 64 bit, so we need to shift 32 bit back + return y << 32; +} diff --git a/tests/math/float.spec.ts b/tests/math/float.spec.ts index c3161d0..ae73462 100644 --- a/tests/math/float.spec.ts +++ b/tests/math/float.spec.ts @@ -15,7 +15,7 @@ function toFloat(value: number, decimals: number = 64): bigint { return BigInt(d.toString()); } -describe('NFTExample', () => { +describe('MathExample', () => { let blockchain: Blockchain; let deployer: SandboxContract; let mathContract: SandboxContract; @@ -104,7 +104,7 @@ describe('NFTExample', () => { op: 0n, } ); - console.log("Add") + console.log('Add'); printTransactionFees(addTxs.transactions); const addResult = await mathContract.getResult(); expect(Number(addResult)).toBeCloseTo(Number(toFloat(10.25))); @@ -123,7 +123,7 @@ describe('NFTExample', () => { op: 1n, } ); - console.log("Sub") + console.log('Sub'); printTransactionFees(subTxs.transactions); const subResult = await mathContract.getResult(); expect(Number(subResult)).toBeCloseTo(Number(toFloat(-9.75))); @@ -142,7 +142,7 @@ describe('NFTExample', () => { op: 2n, } ); - console.log("Mul") + console.log('Mul'); printTransactionFees(mulTxs.transactions); const mulResult = await mathContract.getResult(); expect(Number(mulResult)).toBeCloseTo(Number(toFloat(2.5))); @@ -161,9 +161,47 @@ describe('NFTExample', () => { op: 3n, } ); - console.log("Div") + console.log('Div'); printTransactionFees(divTxs.transactions); const divResult = await mathContract.getResult(); expect(Number(divResult)).toBeCloseTo(Number(toFloat(0.025))); }); + + it('Sqrt 0.05', async () => { + const sqrtTxs = await mathContract.send( + deployer.getSender(), + { + value: toNano('0.05'), + }, + { + $$type: 'Arithmetic', + floatA: toFloat(0.25), + floatB: 0n, + op: 4n, + } + ); + console.log('Sqrt'); + printTransactionFees(sqrtTxs.transactions); + const sqrtResult = await mathContract.getResult(); + expect(Number(sqrtResult)).toBeCloseTo(Number(toFloat(0.5))); + }); + + it('Sqrt 25', async () => { + const sqrtTxs = await mathContract.send( + deployer.getSender(), + { + value: toNano('0.05'), + }, + { + $$type: 'Arithmetic', + floatA: toFloat(25), + floatB: 0n, + op: 4n, + } + ); + console.log('Sqrt'); + printTransactionFees(sqrtTxs.transactions); + const sqrtResult = await mathContract.getResult(); + expect(Number(sqrtResult)).toBeCloseTo(Number(toFloat(5))); + }); }); From 50c5fd41bd82c3b6c5f9e71c8973ea7484c45553 Mon Sep 17 00:00:00 2001 From: alan890104 Date: Sun, 10 Dec 2023 23:10:27 +0800 Subject: [PATCH 2/4] chore: Add CI workflow for automated testing --- .github/workflows/ci.yaml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/ci.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..df50d43 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,30 @@ +name: CI + +# trigger on Pull request for all branches and on push for master branch +on: + pull_request: + branches: + - '*' + push: + branches: + - master +jobs: + build: + name: Test + runs-on: ubuntu-latest + strategy: + matrix: + node: [14, 16, 18] + steps: + - uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: 'yarn' + - name: Install dependencies + run: yarn install --frozen-lockfile + - name: Build contracts + run: yarn build + - name: Run tests + run: yarn test From c1497b087ce6c76936c5e88f81295b85e1518aef Mon Sep 17 00:00:00 2001 From: alan890104 Date: Sun, 10 Dec 2023 23:12:04 +0800 Subject: [PATCH 3/4] fix: Remove Node.js version 14 from CI workflow --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index df50d43..6a2c315 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [16, 18] steps: - uses: actions/checkout@v4 - name: Setup node From 1c4acc6013fce733df2232154dd528f9d0f49bf1 Mon Sep 17 00:00:00 2001 From: ipromise2324 <168allen55@gmail.com> Date: Mon, 11 Dec 2023 00:30:16 +0800 Subject: [PATCH 4/4] feat: add throw division by zero error test --- tests/math/float.spec.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/math/float.spec.ts b/tests/math/float.spec.ts index ae73462..8e1e156 100644 --- a/tests/math/float.spec.ts +++ b/tests/math/float.spec.ts @@ -83,13 +83,11 @@ describe('MathExample', () => { expect(safeDivResult).toEqual(5270498306774157604n); }); - // How to test throw error? - // it('Should throw errorCode 4 if div by 0', async () => { - // const t = async () => { - // await mathContract.getDivisionByZero(); - // }; - // expect(t()).toThrowError(GetMethodError); - // }); + it('Should throw errorCode 4 if div by 0', async () => { + await mathContract.getDivisionByZero().catch((e) => { + expect(e.exitCode).toEqual(4); + }); + }); it('0.25 + 10', async () => { const addTxs = await mathContract.send(