xref: /aosp_15_r20/external/perfetto/ui/src/base/bigint_math_unittest.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2023 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {BigintMath as BIM} from './bigint_math';
16
17describe('BigIntMath', () => {
18  describe('bitCeil', () => {
19    it('rounds powers of 2 to themselves', () => {
20      expect(BIM.bitCeil(1n)).toBe(1n);
21      expect(BIM.bitCeil(2n)).toBe(2n);
22      expect(BIM.bitCeil(4n)).toBe(4n);
23      expect(BIM.bitCeil(4294967296n)).toBe(4294967296n);
24      expect(BIM.bitCeil(2305843009213693952n)).toBe(2305843009213693952n);
25    });
26
27    it('rounds non powers of 2 up to nearest power of 2', () => {
28      expect(BIM.bitCeil(3n)).toBe(4n);
29      expect(BIM.bitCeil(11n)).toBe(16n);
30      expect(BIM.bitCeil(33n)).toBe(64n);
31      expect(BIM.bitCeil(63n)).toBe(64n);
32      expect(BIM.bitCeil(1234567890123456789n)).toBe(2305843009213693952n);
33    });
34
35    it('rounds 0 or negative values up to 1', () => {
36      expect(BIM.bitCeil(0n)).toBe(1n);
37      expect(BIM.bitCeil(-123n)).toBe(1n);
38    });
39  });
40
41  describe('bitFloor', () => {
42    it('rounds powers of 2 to themselves', () => {
43      expect(BIM.bitFloor(1n)).toBe(1n);
44      expect(BIM.bitFloor(2n)).toBe(2n);
45      expect(BIM.bitFloor(4n)).toBe(4n);
46      expect(BIM.bitFloor(4294967296n)).toBe(4294967296n);
47      expect(BIM.bitFloor(2305843009213693952n)).toBe(2305843009213693952n);
48    });
49
50    it('rounds non powers of 2 down to nearest power of 2', () => {
51      expect(BIM.bitFloor(3n)).toBe(2n);
52      expect(BIM.bitFloor(11n)).toBe(8n);
53      expect(BIM.bitFloor(33n)).toBe(32n);
54      expect(BIM.bitFloor(63n)).toBe(32n);
55      expect(BIM.bitFloor(1234567890123456789n)).toBe(1152921504606846976n);
56    });
57
58    it('rounds 0 or negative values up to 1', () => {
59      expect(BIM.bitFloor(0n)).toBe(1n);
60      expect(BIM.bitFloor(-123n)).toBe(1n);
61    });
62  });
63
64  describe('log2', () => {
65    it('calcs exact powers of 2', () => {
66      expect(BIM.log2(1n)).toBe(0);
67      expect(BIM.log2(2n)).toBe(1);
68      expect(BIM.log2(4n)).toBe(2);
69      expect(BIM.log2(4294967296n)).toBe(32);
70      expect(BIM.log2(2305843009213693952n)).toBe(61);
71    });
72
73    it('rounds non powers of 2 down to nearest power of 2', () => {
74      expect(BIM.log2(3n)).toBe(1);
75      expect(BIM.log2(11n)).toBe(3);
76      expect(BIM.log2(33n)).toBe(5);
77      expect(BIM.log2(63n)).toBe(5);
78      expect(BIM.log2(1234567890123456789n)).toBe(60);
79    });
80
81    it('returns 0 for 0n negative numbers', () => {
82      expect(BIM.log2(0n)).toBe(0);
83      expect(BIM.log2(-123n)).toBe(0);
84    });
85  });
86
87  describe('quant', () => {
88    it('should round an int to the nearest multiple of a stepsize', () => {
89      expect(BIM.quant(0n, 2n)).toEqual(0n);
90      expect(BIM.quant(1n, 2n)).toEqual(2n);
91      expect(BIM.quant(2n, 2n)).toEqual(2n);
92      expect(BIM.quant(3n, 2n)).toEqual(4n);
93      expect(BIM.quant(4n, 2n)).toEqual(4n);
94
95      expect(BIM.quant(0n, 3n)).toEqual(0n);
96      expect(BIM.quant(1n, 3n)).toEqual(0n);
97      expect(BIM.quant(2n, 3n)).toEqual(3n);
98      expect(BIM.quant(3n, 3n)).toEqual(3n);
99      expect(BIM.quant(4n, 3n)).toEqual(3n);
100      expect(BIM.quant(5n, 3n)).toEqual(6n);
101      expect(BIM.quant(6n, 3n)).toEqual(6n);
102    });
103
104    it('should return value if stepsize is smaller than 1', () => {
105      expect(BIM.quant(123n, 0n)).toEqual(123n);
106      expect(BIM.quant(123n, -10n)).toEqual(123n);
107    });
108  });
109
110  describe('quantFloor', () => {
111    it('should quantize a number to the nearest multiple of a stepsize', () => {
112      expect(BIM.quantFloor(10n, 2n)).toEqual(10n);
113      expect(BIM.quantFloor(11n, 2n)).toEqual(10n);
114      expect(BIM.quantFloor(12n, 2n)).toEqual(12n);
115      expect(BIM.quantFloor(13n, 2n)).toEqual(12n);
116
117      expect(BIM.quantFloor(9n, 4n)).toEqual(8n);
118      expect(BIM.quantFloor(10n, 4n)).toEqual(8n);
119      expect(BIM.quantFloor(11n, 4n)).toEqual(8n);
120      expect(BIM.quantFloor(12n, 4n)).toEqual(12n);
121      expect(BIM.quantFloor(13n, 4n)).toEqual(12n);
122    });
123
124    it('should handle negative numbers', () => {
125      expect(BIM.quantFloor(-4n, 10n)).toEqual(-10n);
126      expect(BIM.quantFloor(-10n, 10n)).toEqual(-10n);
127      expect(BIM.quantFloor(-11n, 10n)).toEqual(-20n);
128    });
129
130    it('should return value if stepsize is smaller than 1', () => {
131      expect(BIM.quantFloor(123n, 0n)).toEqual(123n);
132      expect(BIM.quantFloor(123n, -10n)).toEqual(123n);
133    });
134  });
135
136  describe('quantCeil', () => {
137    it('should round an int up to the nearest multiple of a stepsize', () => {
138      expect(BIM.quantCeil(10n, 2n)).toEqual(10n);
139      expect(BIM.quantCeil(11n, 2n)).toEqual(12n);
140      expect(BIM.quantCeil(12n, 2n)).toEqual(12n);
141      expect(BIM.quantCeil(13n, 2n)).toEqual(14n);
142
143      expect(BIM.quantCeil(9n, 4n)).toEqual(12n);
144      expect(BIM.quantCeil(10n, 4n)).toEqual(12n);
145      expect(BIM.quantCeil(11n, 4n)).toEqual(12n);
146      expect(BIM.quantCeil(12n, 4n)).toEqual(12n);
147      expect(BIM.quantCeil(13n, 4n)).toEqual(16n);
148    });
149
150    it('should handle negative numbers', () => {
151      expect(BIM.quantCeil(-4n, 10n)).toEqual(0n);
152      expect(BIM.quantCeil(-10n, 10n)).toEqual(-10n);
153      expect(BIM.quantCeil(-11n, 10n)).toEqual(-10n);
154    });
155
156    it('should return value if stepsize is smaller than 1', () => {
157      expect(BIM.quantCeil(123n, 0n)).toEqual(123n);
158      expect(BIM.quantCeil(123n, -10n)).toEqual(123n);
159    });
160  });
161
162  describe('quantRound', () => {
163    it('should quantize a number to the nearest multiple of a stepsize', () => {
164      expect(BIM.quant(0n, 2n)).toEqual(0n);
165      expect(BIM.quant(1n, 2n)).toEqual(2n);
166      expect(BIM.quant(2n, 2n)).toEqual(2n);
167      expect(BIM.quant(3n, 2n)).toEqual(4n);
168      expect(BIM.quant(4n, 2n)).toEqual(4n);
169
170      expect(BIM.quant(0n, 3n)).toEqual(0n);
171      expect(BIM.quant(1n, 3n)).toEqual(0n);
172      expect(BIM.quant(2n, 3n)).toEqual(3n);
173      expect(BIM.quant(3n, 3n)).toEqual(3n);
174      expect(BIM.quant(4n, 3n)).toEqual(3n);
175      expect(BIM.quant(5n, 3n)).toEqual(6n);
176      expect(BIM.quant(6n, 3n)).toEqual(6n);
177    });
178
179    it('should return value if stepsize is smaller than 1', () => {
180      expect(BIM.quant(123n, 0n)).toEqual(123n);
181      expect(BIM.quant(123n, -10n)).toEqual(123n);
182    });
183  });
184
185  describe('max', () => {
186    it('should return the greater of two numbers', () => {
187      expect(BIM.max(5n, 8n)).toEqual(8n);
188      expect(BIM.max(3n, 7n)).toEqual(7n);
189      expect(BIM.max(6n, 6n)).toEqual(6n);
190      expect(BIM.max(-7n, -12n)).toEqual(-7n);
191    });
192  });
193
194  describe('min', () => {
195    it('should return the smaller of two numbers', () => {
196      expect(BIM.min(5n, 8n)).toEqual(5n);
197      expect(BIM.min(3n, 7n)).toEqual(3n);
198      expect(BIM.min(6n, 6n)).toEqual(6n);
199      expect(BIM.min(-7n, -12n)).toEqual(-12n);
200    });
201  });
202
203  describe('popcount', () => {
204    it('should return the number of set bits in an integer', () => {
205      expect(BIM.popcount(0n)).toBe(0);
206      expect(BIM.popcount(1n)).toBe(1);
207      expect(BIM.popcount(2n)).toBe(1);
208      expect(BIM.popcount(3n)).toBe(2);
209      expect(BIM.popcount(4n)).toBe(1);
210      expect(BIM.popcount(5n)).toBe(2);
211      expect(BIM.popcount(3462151285050974216n)).toBe(10);
212    });
213
214    it('should throw when presented with a negative integer', () => {
215      expect(() => BIM.popcount(-1n)).toThrowError(
216        "Can't get popcount of negative number -1",
217      );
218    });
219  });
220
221  describe('ratio', () => {
222    it('should return ratio as number', () => {
223      expect(BIM.ratio(0n, 1n)).toBeCloseTo(0);
224      expect(BIM.ratio(1n, 1n)).toBeCloseTo(1);
225      expect(BIM.ratio(1n, 2n)).toBeCloseTo(0.5);
226      expect(BIM.ratio(1n, 100n)).toBeCloseTo(0.01);
227      expect(
228        BIM.ratio(
229          987654321098765432109876543210n,
230          123456789012345678901234567890n,
231        ),
232      ).toBeCloseTo(8);
233      expect(
234        BIM.ratio(
235          123456789012345678901234567890n,
236          987654321098765432109876543210n,
237        ),
238      ).toBeCloseTo(0.125, 3);
239    });
240  });
241
242  describe('abs', () => {
243    test('should return the absolute value of a positive BigInt', () => {
244      const result = BIM.abs(12345678901234567890n);
245      expect(result).toEqual(12345678901234567890n);
246    });
247
248    test('should return the absolute value of a negative BigInt', () => {
249      const result = BIM.abs(-12345678901234567890n);
250      expect(result).toEqual(12345678901234567890n);
251    });
252
253    test('should return the absolute value of zero', () => {
254      const result = BIM.abs(0n);
255      expect(result).toEqual(0n);
256    });
257  });
258});
259