/* This file is part of Jellyfish. Jellyfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jellyfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jellyfish. If not, see . */ #ifndef __JELLYFISH_DIVISOR_HPP__ #define __JELLYFISH_DIVISOR_HPP__ #include #ifdef HAVE_CONFIG_H #include #endif namespace jflib { class divisor64 { const uint64_t d_; #ifdef HAVE_INT128 const uint16_t p_; const unsigned __int128 m_; #endif template static T div_ceil(T x, T y) { T q = x / y; T r = x % y; return q + (r > 0); } template static uint16_t ceilLog2(T x, uint16_t r = 0, uint16_t i = 0) { if(x > 1) return ceilLog2(x >> 1, r + 1, i | (x & 1)); return r + i; } public: explicit divisor64(uint64_t d) : d_(d) #ifdef HAVE_INT128 , p_(ceilLog2(d_)), m_((div_ceil((unsigned __int128)1 << (64 + p_), (unsigned __int128)d_)) & (uint64_t)-1) #endif { } divisor64() : d_(0) #ifdef HAVE_INT128 , p_(0), m_(0) #endif { } explicit divisor64(const divisor64& rhs) : d_(rhs.d_) #ifdef HAVE_INT128 , p_(rhs.p_), m_(rhs.m_) #endif { } inline uint64_t divide(const uint64_t n) const { #ifdef HAVE_INT128 switch(m_) { case 0: return n >> p_; default: const unsigned __int128 n_ = (unsigned __int128)n; return (n_ + ((n_ * m_) >> 64)) >> p_; } #else return n / d_; #endif } inline uint64_t remainder(uint64_t n) const { #ifdef HAVE_INT128 switch(m_) { case 0: return n & (((uint64_t)1 << p_) - 1); default: return n - divide(n) * d_; } #else return n % d_; #endif } // Euclidian division: d.division(n, q, r) sets q <- n / d and r // <- n % d. This is faster than doing each independently. inline void division(uint64_t n, uint64_t &q, uint64_t &r) const { #ifdef HAVE_INT128 switch(m_) { case 0: q = n >> p_; r = n & (((uint64_t)1 << p_) - 1); break; default: q = divide(n); r = n - q * d_; break; } #else q = n / d_; r = n % d_; #endif } uint64_t d() const { return d_; } uint64_t p() const { #ifdef HAVE_INT128 return p_; #else return 0; #endif } uint64_t m() const { #ifdef HAVE_INT128 return m_; #else return 0; #endif } }; inline uint64_t operator/(uint64_t n, const divisor64& d) { return d.divide(n); } inline uint64_t operator%(uint64_t n, const divisor64& d) { return d.remainder(n); } inline std::ostream& operator<<(std::ostream& os, const divisor64& d) { return os << "d:" << d.d() << ",p:" << d.p() << ",m:" << d.m(); } } // namespace jflib #endif /* __JELLYFISH_DIVISOR_HPP__ */