xref: /aosp_15_r20/external/perfetto/ui/src/base/bigint_math.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2023 The Android Open Source Project
2*6dbdd20aSAndroid Build Coastguard Worker//
3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*6dbdd20aSAndroid Build Coastguard Worker//
7*6dbdd20aSAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*6dbdd20aSAndroid Build Coastguard Worker//
9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License.
14*6dbdd20aSAndroid Build Coastguard Worker
15*6dbdd20aSAndroid Build Coastguard Workerexport class BigintMath {
16*6dbdd20aSAndroid Build Coastguard Worker  static INT64_MAX: bigint = 2n ** 63n - 1n;
17*6dbdd20aSAndroid Build Coastguard Worker  static INT64_MIN: bigint = -(2n ** 63n);
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker  // Returns the smallest integral power of 2 that is not smaller than n.
20*6dbdd20aSAndroid Build Coastguard Worker  // If n is less than or equal to 0, returns 1.
21*6dbdd20aSAndroid Build Coastguard Worker  static bitCeil(n: bigint): bigint {
22*6dbdd20aSAndroid Build Coastguard Worker    let result = 1n;
23*6dbdd20aSAndroid Build Coastguard Worker    while (result < n) {
24*6dbdd20aSAndroid Build Coastguard Worker      result <<= 1n;
25*6dbdd20aSAndroid Build Coastguard Worker    }
26*6dbdd20aSAndroid Build Coastguard Worker    return result;
27*6dbdd20aSAndroid Build Coastguard Worker  }
28*6dbdd20aSAndroid Build Coastguard Worker
29*6dbdd20aSAndroid Build Coastguard Worker  // Returns the largest integral power of 2 which is not greater than n.
30*6dbdd20aSAndroid Build Coastguard Worker  // If n is less than or equal to 0, returns 1.
31*6dbdd20aSAndroid Build Coastguard Worker  static bitFloor(n: bigint): bigint {
32*6dbdd20aSAndroid Build Coastguard Worker    let result = 1n;
33*6dbdd20aSAndroid Build Coastguard Worker    while (result << 1n <= n) {
34*6dbdd20aSAndroid Build Coastguard Worker      result <<= 1n;
35*6dbdd20aSAndroid Build Coastguard Worker    }
36*6dbdd20aSAndroid Build Coastguard Worker    return result;
37*6dbdd20aSAndroid Build Coastguard Worker  }
38*6dbdd20aSAndroid Build Coastguard Worker
39*6dbdd20aSAndroid Build Coastguard Worker  // Returns the largest integral value x where 2^x is not greater than n.
40*6dbdd20aSAndroid Build Coastguard Worker  static log2(n: bigint): number {
41*6dbdd20aSAndroid Build Coastguard Worker    let result = 1n;
42*6dbdd20aSAndroid Build Coastguard Worker    let log2 = 0;
43*6dbdd20aSAndroid Build Coastguard Worker    while (result << 1n <= n) {
44*6dbdd20aSAndroid Build Coastguard Worker      result <<= 1n;
45*6dbdd20aSAndroid Build Coastguard Worker      ++log2;
46*6dbdd20aSAndroid Build Coastguard Worker    }
47*6dbdd20aSAndroid Build Coastguard Worker    return log2;
48*6dbdd20aSAndroid Build Coastguard Worker  }
49*6dbdd20aSAndroid Build Coastguard Worker
50*6dbdd20aSAndroid Build Coastguard Worker  // Returns the integral multiple of step which is closest to n.
51*6dbdd20aSAndroid Build Coastguard Worker  // If step is less than or equal to 0, returns n.
52*6dbdd20aSAndroid Build Coastguard Worker  static quant(n: bigint, step: bigint): bigint {
53*6dbdd20aSAndroid Build Coastguard Worker    step = BigintMath.max(1n, step);
54*6dbdd20aSAndroid Build Coastguard Worker    const halfStep = step / 2n;
55*6dbdd20aSAndroid Build Coastguard Worker    return step * ((n + halfStep) / step);
56*6dbdd20aSAndroid Build Coastguard Worker  }
57*6dbdd20aSAndroid Build Coastguard Worker
58*6dbdd20aSAndroid Build Coastguard Worker  // Returns the largest integral multiple of step which is not larger than n.
59*6dbdd20aSAndroid Build Coastguard Worker  // If step is less than or equal to 0, returns n.
60*6dbdd20aSAndroid Build Coastguard Worker  static quantFloor(n: bigint, step: bigint): bigint {
61*6dbdd20aSAndroid Build Coastguard Worker    step = BigintMath.max(1n, step);
62*6dbdd20aSAndroid Build Coastguard Worker    if (n >= 0) {
63*6dbdd20aSAndroid Build Coastguard Worker      return n - (n % step);
64*6dbdd20aSAndroid Build Coastguard Worker    } else {
65*6dbdd20aSAndroid Build Coastguard Worker      // If we're negative, just subtract one more "step", unless we're already
66*6dbdd20aSAndroid Build Coastguard Worker      // aligned to a step then do nothing.
67*6dbdd20aSAndroid Build Coastguard Worker      return n - (n % step) - (n % step === 0n ? 0n : step);
68*6dbdd20aSAndroid Build Coastguard Worker    }
69*6dbdd20aSAndroid Build Coastguard Worker  }
70*6dbdd20aSAndroid Build Coastguard Worker
71*6dbdd20aSAndroid Build Coastguard Worker  // Returns the smallest integral multiple of step which is not smaller than n.
72*6dbdd20aSAndroid Build Coastguard Worker  // If step is less than or equal to 0, returns n.
73*6dbdd20aSAndroid Build Coastguard Worker  static quantCeil(n: bigint, step: bigint): bigint {
74*6dbdd20aSAndroid Build Coastguard Worker    step = BigintMath.max(1n, step);
75*6dbdd20aSAndroid Build Coastguard Worker    if (n >= 0) {
76*6dbdd20aSAndroid Build Coastguard Worker      return n - (n % step) + (n % step === 0n ? 0n : step);
77*6dbdd20aSAndroid Build Coastguard Worker    } else {
78*6dbdd20aSAndroid Build Coastguard Worker      return n - (n % step);
79*6dbdd20aSAndroid Build Coastguard Worker    }
80*6dbdd20aSAndroid Build Coastguard Worker  }
81*6dbdd20aSAndroid Build Coastguard Worker
82*6dbdd20aSAndroid Build Coastguard Worker  // Returns the greater of a and b.
83*6dbdd20aSAndroid Build Coastguard Worker  static max(a: bigint, b: bigint): bigint {
84*6dbdd20aSAndroid Build Coastguard Worker    return a > b ? a : b;
85*6dbdd20aSAndroid Build Coastguard Worker  }
86*6dbdd20aSAndroid Build Coastguard Worker
87*6dbdd20aSAndroid Build Coastguard Worker  // Returns the smaller of a and b.
88*6dbdd20aSAndroid Build Coastguard Worker  static min(a: bigint, b: bigint): bigint {
89*6dbdd20aSAndroid Build Coastguard Worker    return a < b ? a : b;
90*6dbdd20aSAndroid Build Coastguard Worker  }
91*6dbdd20aSAndroid Build Coastguard Worker
92*6dbdd20aSAndroid Build Coastguard Worker  // Returns the number of 1 bits in n.
93*6dbdd20aSAndroid Build Coastguard Worker  static popcount(n: bigint): number {
94*6dbdd20aSAndroid Build Coastguard Worker    if (n < 0n) {
95*6dbdd20aSAndroid Build Coastguard Worker      throw Error(`Can\'t get popcount of negative number ${n}`);
96*6dbdd20aSAndroid Build Coastguard Worker    }
97*6dbdd20aSAndroid Build Coastguard Worker    let count = 0;
98*6dbdd20aSAndroid Build Coastguard Worker    while (n) {
99*6dbdd20aSAndroid Build Coastguard Worker      if (n & 1n) {
100*6dbdd20aSAndroid Build Coastguard Worker        ++count;
101*6dbdd20aSAndroid Build Coastguard Worker      }
102*6dbdd20aSAndroid Build Coastguard Worker      n >>= 1n;
103*6dbdd20aSAndroid Build Coastguard Worker    }
104*6dbdd20aSAndroid Build Coastguard Worker    return count;
105*6dbdd20aSAndroid Build Coastguard Worker  }
106*6dbdd20aSAndroid Build Coastguard Worker
107*6dbdd20aSAndroid Build Coastguard Worker  // Return the ratio between two bigints as a number.
108*6dbdd20aSAndroid Build Coastguard Worker  static ratio(dividend: bigint, divisor: bigint): number {
109*6dbdd20aSAndroid Build Coastguard Worker    return Number(dividend) / Number(divisor);
110*6dbdd20aSAndroid Build Coastguard Worker  }
111*6dbdd20aSAndroid Build Coastguard Worker
112*6dbdd20aSAndroid Build Coastguard Worker  // Calculates the absolute value of a n.
113*6dbdd20aSAndroid Build Coastguard Worker  static abs(n: bigint) {
114*6dbdd20aSAndroid Build Coastguard Worker    return n < 0n ? -1n * n : n;
115*6dbdd20aSAndroid Build Coastguard Worker  }
116*6dbdd20aSAndroid Build Coastguard Worker}
117