intmath
Version:
A package to perform precise 64 and 128-bit math operations in typescript.
221 lines (211 loc) • 7.91 kB
text/typescript
/*
* A library to perform precise integer math operations on 64 and 128-bit signed
* numbers.
*
* Copyright (c) 2017 Venelin Efremov
*
* License:
* MIT, see LICENSE file for details.
*/
import * as assert from "assert";
import {Int64, Int128} from "../intmath";
const tabu:Int64[] = [
Int64.fromInt(0),
Int64.fromInt(1),
Int64.fromInt(2),
Int64.fromInt(3),
Int64.fromInt(4),
Int64.fromInt(5),
Int64.fromInt(6),
Int64.fromInt(7),
Int64.fromInt(8),
Int64.fromInt(9),
Int64.fromInt(10),
Int64.fromInt(11),
Int64.fromInt(12),
Int64.fromInt(13),
Int64.fromInt(14),
Int64.fromInt(15),
Int64.fromInt(16),
Int64.fromInt(1000),
Int64.fromInt(2003),
Int64.fromInt(32765),
Int64.fromInt(32766),
Int64.fromInt(32767),
Int64.fromInt(32768),
Int64.fromInt(32769),
Int64.fromInt(32760),
Int64.fromInt(65533),
Int64.fromInt(65534),
Int64.fromInt(65535),
Int64.fromInt(65536),
Int64.fromInt(65537),
Int64.fromInt(65538),
Int64.fromInt(0x7ffffffe),
Int64.fromInt(0x7fffffff),
Int64.fromNumber(0x80000000),
Int64.fromNumber(0x80000001),
new Int64(0, 0x70000000),
new Int64(0x80000000, 0x70000000),
new Int64(0x80000001, 0x70000000),
new Int64(0xffffffff, 0x7fffffff),
new Int64(0x8fffffff, 0x7fffffff),
new Int64(0x8ffffff1, 0x7fffffff),
new Int64(0, 0x7fffffff),
new Int64(0x80000000, 0x7fffffff),
new Int64(0x00000001, 0x7fffffff),
];
const ZERO:Int64 = new Int64(0, 0);
function dump(a:number[], msg:string):void {
let r:string = "";
for (let idx = a.length - 1; idx >= 0; idx--)
{
r += a[idx].toString(16) + ",";
}
console.log(msg, r);
}
function divTest() {
let n = tabu.length;
for (let i = 0; i < n; i++)
for (let j = 1;j< n; j++) {
let uu = tabu[i];
let vu = tabu[j];
let qu = uu.divide(vu);
let ru = uu.subtract(qu.multiply(vu));
if (qu.greaterThan(uu) || ru.greaterThanOrEqual(vu)) {
console.log("Error %d/%d, got %d rem %d",
uu.toNumber(), vu.toNumber(), qu.toNumber(), ru.toNumber());
}
}
}
describe("Int64 tests", () => {
it("load asm code", () => Int64.init());
it('Zero test', () => {
assert.equal(ZERO.low, 0);
assert.equal(ZERO.high, 0);
});
it('Add test', () => {
assert.deepEqual(ZERO.add(ZERO), ZERO);
let one = Int64.fromInt(1);
assert.deepEqual(one.add(one.negate()), ZERO);
let five = Int64.fromInt(5);
let two = Int64.fromInt(2);
let three = Int64.fromInt(3);
assert.deepEqual(five.add(two.negate()), three); // 5 + (-2) = 3
assert.deepEqual(five.negate().add(two), three.negate()); // -5 + 2 = -3
assert.deepEqual(
new Int64(0xfffffffe, 0xffffffff).add(five), three);
});
it('Compare test', () => {
let one = Int64.fromInt(1);
assert.ok(ZERO.equals(ZERO));
assert.ok(one.equals(one));
assert.ok(one.notEquals(ZERO));
let five = Int64.fromInt(5);
let two = Int64.fromInt(2);
assert.ok(five.greaterThan(ZERO));
assert.ok(five.greaterThan(two));
assert.ok(five.greaterThan(two.negate()));
assert.ok(five.negate().lessThan(two));
assert.ok(five.negate().lessThan(ZERO));
assert.ok(five.negate().negate().equals(five));
});
it('Multiply test', () => {
assert.deepEqual(ZERO.multiply(ZERO), ZERO);
let one = Int64.fromInt(1);
assert.deepEqual(one.multiply(one.negate()), one.negate());
let five = Int64.fromInt(5);
let twoThousand = Int64.fromInt(2000);
let tenThousand = Int64.fromInt(10000);
assert.deepEqual(five.multiply(twoThousand), tenThousand);
assert.deepEqual(five.negate().multiply(twoThousand), tenThousand.negate());
assert.deepEqual(five.multiply(twoThousand.negate()), tenThousand.negate());
assert.deepEqual(five.negate().multiply(twoThousand.negate()), tenThousand);
let tst = new Int64(0x49FFFFE9, 0x16140148);
assert.deepEqual(tst.multiply(tst), new Int64(0xB4000211, 0xBDCBC502));
});
it('Shift test', () => {
let xA5 = new Int64(0xa5a5a5a5, 0xa5a5a5a5);
assert.deepEqual(xA5.shrUnsigned(1), new Int64(0xd2d2d2d2, 0x52d2d2d2));
assert.deepEqual(
new Int64(0, 1).shrUnsigned(1), new Int64(0x80000000, 0));
assert.deepEqual(
new Int64(0, 0x12345678).shrUnsigned(32), new Int64(0x12345678, 0));
assert.deepEqual(
new Int64(0, 1).shrUnsigned(16), new Int64(0x10000, 0));
assert.deepEqual(
new Int64(0, 0x12345678).shr(32), new Int64(0x12345678, 0));
assert.deepEqual(
new Int64(0, 1).shr(16), new Int64(0x10000, 0));
assert.deepEqual(
Int64.fromInt(-100).shr(2), Int64.fromInt(-25));
assert.deepEqual(xA5.shl(1), new Int64(0x4b4b4b4a, 0x4b4b4b4b));
assert.deepEqual(
new Int64(0x12345678, 0).shl(32), new Int64(0, 0x12345678));
assert.deepEqual(
new Int64(0x12345678, 0).shl(16), new Int64(0x56780000, 0x1234));
});
it('Division tests', () => {
let one = Int64.fromInt(1);
let tst = new Int64(0x49FFFFE9, 0x16140148);
let divisor = new Int64(0x945A00D1, 0x05);
assert.deepEqual(ZERO.divide(one), ZERO);
assert.deepEqual(one.divide(one.negate()), one.negate());
let five = Int64.fromInt(5);
let twoThousand = Int64.fromInt(2000);
let tenThousand = Int64.fromInt(10000);
assert.deepEqual(tenThousand.divide(twoThousand), five);
assert.deepEqual(tenThousand.negate().divide(twoThousand), five.negate());
assert.deepEqual(tenThousand.divide(twoThousand.negate()), five.negate());
assert.deepEqual(tenThousand.negate().divide(twoThousand.negate()), five);
assert.deepEqual(tst.divide(divisor), new Int64(0x03F4FEC5, 0));
assert.deepEqual(tst.modulo(divisor), new Int64(0x99BA0114, 0));
divTest();
});
});
function dump128(r:Int128, name:string): void {
console.log("%s(%s, %s, %s, %s)",
name,
(r.d0 >>> 0).toString(16),
(r.d1 >>> 0).toString(16),
(r.d2 >>> 0).toString(16),
(r.d3 >>> 0).toString(16));
}
describe("Int128 tests", () => {
it("load asm code", () => Int64.init());
it("Add/Subtract test", () => {
let one = new Int128(1, 0, 0, 0);
let carryTest = new Int128(0xffffffff, 0xffffffff, 0xff, 0);
let r = one.add(carryTest);
assert.deepEqual(r, new Int128(0, 0, 0x100, 0));
let r2 = r.subtract(carryTest);
let r3 = r.subtract(one);
assert.deepEqual(r2, one);
assert.deepEqual(r3, carryTest);
});
it("Negate test", () => {
let zero = new Int128(0, 0, 0, 0);
let one = new Int128(1, 0, 0, 0);
let negOne = one.negate();
assert.deepEqual(one.add(negOne), zero);
assert.deepEqual(zero.negate(), zero);
assert.deepEqual(negOne.negate(), one);
assert.deepEqual(negOne.add(one), zero);
});
it("Mutliply tests", () => {
let carryTest = new Int128(0xffffffff, 0x7fffffff, 0, 0);
let r = carryTest.mul(carryTest);
assert.deepEqual(r, new Int128(1, 0, 0xffffffff, 0x3fffffff));
});
it("Float conversion test", () => {
let n = Math.PI;
let c = Int64.fromNumber(n);
assert.deepEqual(c, Int64.fromInt(3));
});
it("Float operations test", () => {
let n = Int64.fromInt(1000);
let f = 20000000000;
assert.deepEqual(n.mul(3.5), Int64.fromInt(3500));
assert.deepEqual(n.mul(f), Int64.fromNumber(2E13));
});
});