aboutsummaryrefslogtreecommitdiff
path: root/trygub.h
blob: 6b1cfcab1624feda528e46b0b7e4e442361d6ed0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <cstdint>
#include <map>

template <typename BaseT = int, BaseT B_ = 0, typename IndexT = int>
struct TrygubNumber {
  explicit TrygubNumber(BaseT b_ = 0) : b{b_} {}

  constexpr BaseT base() const {
    if constexpr (B_) {
      return B_;
    } else {
      return b;
    }
  }

  // += c * B^i
  void add(int64_t c, IndexT i) {
    while (c != 0) {
      c += digits[i];
      auto t = c / base();
      c -= t * base();
      if ((digits[i] = c) == 0) {
        digits.erase(i);
      }
      c = t;
      i++;
    }
  }

  int signum() const {
    auto it = digits.rbegin();
    if (it == digits.rend()) {
      return 0;
    }
    return it->second > 0 ? 1 : -1;
  }

  BaseT operator[](IndexT i) const {
    auto it = digits.lower_bound(i);
    auto v = it == digits.end() || i != it->first ? 0 : it->second;
    if (it != digits.begin() && std::prev(it)->second < 0) {
      v--;
    }
    return v < 0 ? v + base() : v;
  }

  BaseT most_significant_digit() const {
    auto i = digits.rbegin()->first;
    while (!(*this)[i]) {
      i--;
    }
    return i;
  }

  BaseT b;
  std::map<IndexT, BaseT> digits;
};