1// Big integer base-10 printing library
2// Copyright (c) 2008 Lapo Luchini <lapo@lapo.it>
3
4// Permission to use, copy, modify, and/or distribute this software for any
5// purpose with or without fee is hereby granted, provided that the above
6// copyright notice and this permission notice appear in all copies.
7//
8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
16/** Biggest 10^n integer that can still fit 2^53 when multiplied by 256. */
17const max = 10000000000000;
18
19export class Int10 {
20 /**
21 * Arbitrary length base-10 value.
22 * @param {number} value - Optional initial value (will be 0 otherwise).
23 */
24 constructor(value) {
25 this.buf = [+value || 0];
26 }
27
28 /**
29 * Multiply value by m and add c.
30 * @param {number} m - multiplier, must be 0<m<=256
31 * @param {number} c - value to add, must be c>=0
32 */
33 mulAdd(m, c) {
34 // assert(m > 0)
35 // assert(m <= 256)
36 // assert(c >= 0)
37 let b = this.buf,
38 l = b.length,
39 i, t;
40 for (i = 0; i < l; ++i) {
41 t = b[i] * m + c;
42 if (t < max)
43 c = 0;
44 else {
45 c = 0|(t / max);
46 t -= c * max;
47 }
48 b[i] = t;
49 }
50 if (c > 0)
51 b[i] = c;
52 }
53
54 /**
55 * Subtract value.
56 * @param {number} c - value to subtract
57 */
58 sub(c) {
59 let b = this.buf,
60 l = b.length,
61 i, t;
62 for (i = 0; i < l; ++i) {
63 t = b[i] - c;
64 if (t < 0) {
65 t += max;
66 c = 1;
67 } else
68 c = 0;
69 b[i] = t;
70 }
71 while (b[b.length - 1] === 0)
72 b.pop();
73 }
74
75 /**
76 * Convert to decimal string representation.
77 * @param {number} [base=10] - optional value, only value accepted is 10
78 * @returns {string} The decimal string representation.
79 */
80 toString(base = 10) {
81 if (base != 10)
82 throw new Error('only base 10 is supported');
83 let b = this.buf,
84 s = b[b.length - 1].toString();
85 for (let i = b.length - 2; i >= 0; --i)
86 s += (max + b[i]).toString().substring(1);
87 return s;
88 }
89
90 /**
91 * Convert to Number value representation.
92 * Will probably overflow 2^53 and thus become approximate.
93 * @returns {number} The numeric value.
94 */
95 valueOf() {
96 let b = this.buf,
97 v = 0;
98 for (let i = b.length - 1; i >= 0; --i)
99 v = v * max + b[i];
100 return v;
101 }
102
103 /**
104 * Return value as a simple Number (if it is <= 10000000000000), or return this.
105 * @returns {number | Int10} The simplified value.
106 */
107 simplify() {
108 let b = this.buf;
109 return (b.length == 1) ? b[0] : this;
110 }
111
112}