208 lines
7.9 KiB
TypeScript
208 lines
7.9 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {BigInteger, BigIntExponentiation, BigIntForMultiplication} from '../../src/i18n/big_integer';
|
|
|
|
describe('big integers', () => {
|
|
describe('add', () => {
|
|
it('should add two integers', () => {
|
|
const a = createBigInteger(42);
|
|
const b = createBigInteger(1337);
|
|
|
|
expect(a.add(b).toString()).toEqual('1379');
|
|
});
|
|
|
|
it('should add two integers with a carry', () => {
|
|
const a = createBigInteger(8);
|
|
const b = createBigInteger(995);
|
|
|
|
expect(a.add(b).toString()).toEqual('1003');
|
|
});
|
|
|
|
it('should add two integers beyond the maximum supported JS integer', () => {
|
|
const b31 = createBigInteger(1 << 31);
|
|
|
|
const b32 = b31.add(b31);
|
|
const b33 = b32.add(b32);
|
|
const b34 = b33.add(b33);
|
|
const b35 = b34.add(b34);
|
|
const b36 = b35.add(b35);
|
|
const b37 = b36.add(b36);
|
|
const b38 = b37.add(b37);
|
|
const b39 = b38.add(b38);
|
|
const b40 = b39.add(b39);
|
|
const b41 = b40.add(b40);
|
|
const b42 = b41.add(b41);
|
|
const b43 = b42.add(b42);
|
|
const b44 = b43.add(b43);
|
|
const b45 = b44.add(b44);
|
|
const b46 = b45.add(b45);
|
|
const b47 = b46.add(b46);
|
|
const b48 = b47.add(b47);
|
|
const b49 = b48.add(b48);
|
|
const b50 = b49.add(b49);
|
|
const b51 = b50.add(b50);
|
|
const b52 = b51.add(b51);
|
|
const b53 = b52.add(b52);
|
|
const b54 = b53.add(b53);
|
|
const b55 = b54.add(b54);
|
|
const b56 = b55.add(b55);
|
|
const b57 = b56.add(b56);
|
|
const b58 = b57.add(b57);
|
|
const b59 = b58.add(b58);
|
|
const b60 = b59.add(b59);
|
|
const b61 = b60.add(b60);
|
|
const b62 = b61.add(b61);
|
|
const b63 = b62.add(b62);
|
|
const b64 = b63.add(b63);
|
|
const b65 = b64.add(b64);
|
|
|
|
expect(b32.toString()).toEqual('4294967296');
|
|
expect(b33.toString()).toEqual('8589934592');
|
|
expect(b34.toString()).toEqual('17179869184');
|
|
expect(b35.toString()).toEqual('34359738368');
|
|
expect(b36.toString()).toEqual('68719476736');
|
|
expect(b37.toString()).toEqual('137438953472');
|
|
expect(b38.toString()).toEqual('274877906944');
|
|
expect(b39.toString()).toEqual('549755813888');
|
|
expect(b40.toString()).toEqual('1099511627776');
|
|
expect(b41.toString()).toEqual('2199023255552');
|
|
expect(b42.toString()).toEqual('4398046511104');
|
|
expect(b43.toString()).toEqual('8796093022208');
|
|
expect(b44.toString()).toEqual('17592186044416');
|
|
expect(b45.toString()).toEqual('35184372088832');
|
|
expect(b46.toString()).toEqual('70368744177664');
|
|
expect(b47.toString()).toEqual('140737488355328');
|
|
expect(b48.toString()).toEqual('281474976710656');
|
|
expect(b49.toString()).toEqual('562949953421312');
|
|
expect(b50.toString()).toEqual('1125899906842624');
|
|
expect(b51.toString()).toEqual('2251799813685248');
|
|
expect(b52.toString()).toEqual('4503599627370496');
|
|
expect(b53.toString()).toEqual('9007199254740992');
|
|
expect(b54.toString()).toEqual('18014398509481984');
|
|
|
|
// From here onwards would the result be inaccurate with JavaScript numbers.
|
|
expect(b55.toString()).toEqual('36028797018963968');
|
|
expect(b56.toString()).toEqual('72057594037927936');
|
|
expect(b57.toString()).toEqual('144115188075855872');
|
|
expect(b58.toString()).toEqual('288230376151711744');
|
|
expect(b59.toString()).toEqual('576460752303423488');
|
|
expect(b60.toString()).toEqual('1152921504606846976');
|
|
expect(b61.toString()).toEqual('2305843009213693952');
|
|
expect(b62.toString()).toEqual('4611686018427387904');
|
|
expect(b63.toString()).toEqual('9223372036854775808');
|
|
expect(b64.toString()).toEqual('18446744073709551616');
|
|
expect(b65.toString()).toEqual('36893488147419103232');
|
|
});
|
|
|
|
it('should not mutate the big integer instances', () => {
|
|
const a = createBigInteger(42);
|
|
const b = createBigInteger(1337);
|
|
|
|
a.add(b);
|
|
|
|
expect(a.toString()).toEqual('42');
|
|
expect(b.toString()).toEqual('1337');
|
|
});
|
|
});
|
|
|
|
describe('addToSelf', () => {
|
|
it('should add two integers into the left operand', () => {
|
|
const a = createBigInteger(42);
|
|
const b = createBigInteger(1337);
|
|
|
|
a.addToSelf(b);
|
|
|
|
expect(a.toString()).toEqual('1379');
|
|
});
|
|
|
|
it('should not mutate the right operand', () => {
|
|
const a = createBigInteger(42);
|
|
const b = createBigInteger(1337);
|
|
|
|
a.addToSelf(b);
|
|
|
|
expect(a.toString()).toEqual('1379');
|
|
expect(b.toString()).toEqual('1337');
|
|
});
|
|
});
|
|
|
|
describe('multiplication', () => {
|
|
it('should be correct for 0', () => {
|
|
const a = new BigIntForMultiplication(createBigInteger(0));
|
|
expect(a.multiplyBy(0).toString()).toEqual('0');
|
|
expect(a.multiplyBy(1).toString()).toEqual('0');
|
|
expect(a.multiplyBy(42).toString()).toEqual('0');
|
|
expect(a.multiplyBy(1 << 31).toString()).toEqual('0');
|
|
expect(a.multiplyBy((1 << 31) - 1).toString()).toEqual('0');
|
|
});
|
|
|
|
it('should be correct for 1337', () => {
|
|
const a = new BigIntForMultiplication(createBigInteger(1337));
|
|
expect(a.multiplyBy(0).toString()).toEqual('0');
|
|
expect(a.multiplyBy(1).toString()).toEqual('1337');
|
|
expect(a.multiplyBy(8).toString()).toEqual('10696');
|
|
expect(a.multiplyBy(42).toString()).toEqual('56154');
|
|
expect(a.multiplyBy(1 << 31).toString()).toEqual('2871185637376');
|
|
expect(a.multiplyBy((1 << 31) - 1).toString()).toEqual('2871185636039');
|
|
});
|
|
|
|
it('should multiply and add to an existing big integer', () => {
|
|
const a = new BigIntForMultiplication(createBigInteger(1337));
|
|
const result = createBigInteger(1_000_000);
|
|
a.multiplyByAndAddTo(42, result);
|
|
expect(result.toString()).toEqual('1056154');
|
|
});
|
|
});
|
|
|
|
describe('exponentiation', () => {
|
|
it('should be correct for base-0', () => {
|
|
const base32 = new BigIntExponentiation(0);
|
|
expect(base32.toThePowerOf(0).getValue().toString()).toEqual('1');
|
|
expect(base32.toThePowerOf(1).getValue().toString()).toEqual('0');
|
|
expect(base32.toThePowerOf(2).getValue().toString()).toEqual('0');
|
|
expect(base32.toThePowerOf(3).getValue().toString()).toEqual('0');
|
|
expect(base32.toThePowerOf(8).getValue().toString()).toEqual('0');
|
|
expect(base32.toThePowerOf(12).getValue().toString()).toEqual('0');
|
|
});
|
|
|
|
it('should be correct for base-1', () => {
|
|
const base32 = new BigIntExponentiation(1);
|
|
expect(base32.toThePowerOf(0).getValue().toString()).toEqual('1');
|
|
expect(base32.toThePowerOf(1).getValue().toString()).toEqual('1');
|
|
expect(base32.toThePowerOf(2).getValue().toString()).toEqual('1');
|
|
expect(base32.toThePowerOf(3).getValue().toString()).toEqual('1');
|
|
expect(base32.toThePowerOf(8).getValue().toString()).toEqual('1');
|
|
expect(base32.toThePowerOf(12).getValue().toString()).toEqual('1');
|
|
});
|
|
|
|
it('should be correct for base-42', () => {
|
|
const base32 = new BigIntExponentiation(42);
|
|
expect(base32.toThePowerOf(0).getValue().toString()).toEqual('1');
|
|
expect(base32.toThePowerOf(1).getValue().toString()).toEqual('42');
|
|
expect(base32.toThePowerOf(2).getValue().toString()).toEqual('1764');
|
|
expect(base32.toThePowerOf(3).getValue().toString()).toEqual('74088');
|
|
expect(base32.toThePowerOf(8).getValue().toString()).toEqual('9682651996416');
|
|
expect(base32.toThePowerOf(12).getValue().toString()).toEqual('30129469486639681536');
|
|
});
|
|
|
|
it('should cache the exponents', () => {
|
|
const base32 = new BigIntExponentiation(32);
|
|
|
|
const a = base32.toThePowerOf(4);
|
|
const b = base32.toThePowerOf(4);
|
|
|
|
expect(a).toBe(b);
|
|
});
|
|
});
|
|
|
|
function createBigInteger(value: number): BigInteger {
|
|
return new BigIntForMultiplication(BigInteger.one()).multiplyBy(value);
|
|
}
|
|
});
|