// Boost.Polygon library detail/voronoi_ctypes.hpp header file // Copyright Andrii Sydorchuk 2010-2012. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org for updates, documentation, and revision history. #ifndef BOOST_POLYGON_DETAIL_VORONOI_CTYPES #define BOOST_POLYGON_DETAIL_VORONOI_CTYPES #include #include #include #include #include namespace boost { namespace polygon { namespace detail { typedef boost::int32_t int32; typedef boost::int64_t int64; typedef boost::uint32_t uint32; typedef boost::uint64_t uint64; typedef double fpt64; // If two floating-point numbers in the same format are ordered (x < y), // then they are ordered the same way when their bits are reinterpreted as // sign-magnitude integers. Values are considered to be almost equal if // their integer bits reinterpretations differ in not more than maxUlps units. template struct ulp_comparison; template <> struct ulp_comparison { enum Result { LESS = -1, EQUAL = 0, MORE = 1 }; Result operator()(fpt64 a, fpt64 b, unsigned int maxUlps) const { uint64 ll_a, ll_b; // Reinterpret double bits as 64-bit signed integer. std::memcpy(&ll_a, &a, sizeof(fpt64)); std::memcpy(&ll_b, &b, sizeof(fpt64)); // Positive 0.0 is integer zero. Negative 0.0 is 0x8000000000000000. // Map negative zero to an integer zero representation - making it // identical to positive zero - the smallest negative number is // represented by negative one, and downwards from there. if (ll_a < 0x8000000000000000ULL) ll_a = 0x8000000000000000ULL - ll_a; if (ll_b < 0x8000000000000000ULL) ll_b = 0x8000000000000000ULL - ll_b; // Compare 64-bit signed integer representations of input values. // Difference in 1 Ulp is equivalent to a relative error of between // 1/4,000,000,000,000,000 and 1/8,000,000,000,000,000. if (ll_a > ll_b) return (ll_a - ll_b <= maxUlps) ? EQUAL : LESS; return (ll_b - ll_a <= maxUlps) ? EQUAL : MORE; } }; template struct extened_exponent_fpt_traits; template <> struct extened_exponent_fpt_traits { public: typedef int exp_type; enum { MAX_SIGNIFICANT_EXP_DIF = 54 }; }; // Floating point type wrapper. Allows to extend exponent boundaries to the // integer type range. This class does not handle division by zero, subnormal // numbers or NaNs. template > class extended_exponent_fpt { public: typedef _fpt fpt_type; typedef typename _traits::exp_type exp_type; explicit extended_exponent_fpt(fpt_type val) { val_ = std::frexp(val, &exp_); } extended_exponent_fpt(fpt_type val, exp_type exp) { val_ = std::frexp(val, &exp_); exp_ += exp; } bool is_pos() const { return val_ > 0; } bool is_neg() const { return val_ < 0; } bool is_zero() const { return val_ == 0; } extended_exponent_fpt operator-() const { return extended_exponent_fpt(-val_, exp_); } extended_exponent_fpt operator+(const extended_exponent_fpt& that) const { if (this->val_ == 0.0 || that.exp_ > this->exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return that; } if (that.val_ == 0.0 || this->exp_ > that.exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return *this; } if (this->exp_ >= that.exp_) { exp_type exp_dif = this->exp_ - that.exp_; fpt_type val = std::ldexp(this->val_, exp_dif) + that.val_; return extended_exponent_fpt(val, that.exp_); } else { exp_type exp_dif = that.exp_ - this->exp_; fpt_type val = std::ldexp(that.val_, exp_dif) + this->val_; return extended_exponent_fpt(val, this->exp_); } } extended_exponent_fpt operator-(const extended_exponent_fpt& that) const { if (this->val_ == 0.0 || that.exp_ > this->exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return extended_exponent_fpt(-that.val_, that.exp_); } if (that.val_ == 0.0 || this->exp_ > that.exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return *this; } if (this->exp_ >= that.exp_) { exp_type exp_dif = this->exp_ - that.exp_; fpt_type val = std::ldexp(this->val_, exp_dif) - that.val_; return extended_exponent_fpt(val, that.exp_); } else { exp_type exp_dif = that.exp_ - this->exp_; fpt_type val = std::ldexp(-that.val_, exp_dif) + this->val_; return extended_exponent_fpt(val, this->exp_); } } extended_exponent_fpt operator*(const extended_exponent_fpt& that) const { fpt_type val = this->val_ * that.val_; exp_type exp = this->exp_ + that.exp_; return extended_exponent_fpt(val, exp); } extended_exponent_fpt operator/(const extended_exponent_fpt& that) const { fpt_type val = this->val_ / that.val_; exp_type exp = this->exp_ - that.exp_; return extended_exponent_fpt(val, exp); } extended_exponent_fpt& operator+=(const extended_exponent_fpt& that) { return *this = *this + that; } extended_exponent_fpt& operator-=(const extended_exponent_fpt& that) { return *this = *this - that; } extended_exponent_fpt& operator*=(const extended_exponent_fpt& that) { return *this = *this * that; } extended_exponent_fpt& operator/=(const extended_exponent_fpt& that) { return *this = *this / that; } extended_exponent_fpt sqrt() const { fpt_type val = val_; exp_type exp = exp_; if (exp & 1) { val *= 2.0; --exp; } return extended_exponent_fpt(std::sqrt(val), exp >> 1); } fpt_type d() const { return std::ldexp(val_, exp_); } private: fpt_type val_; exp_type exp_; }; typedef extended_exponent_fpt efpt64; template extended_exponent_fpt<_fpt> get_sqrt(const extended_exponent_fpt<_fpt>& that) { return that.sqrt(); } template bool is_pos(const extended_exponent_fpt<_fpt>& that) { return that.is_pos(); } template bool is_neg(const extended_exponent_fpt<_fpt>& that) { return that.is_neg(); } template bool is_zero(const extended_exponent_fpt<_fpt>& that) { return that.is_zero(); } // Very efficient stack allocated big integer class. // Supports next set of arithmetic operations: +, -, *. template class extended_int { public: extended_int() {} extended_int(int32 that) { if (that > 0) { this->chunks_[0] = that; this->count_ = 1; } else if (that < 0) { this->chunks_[0] = -that; this->count_ = -1; } else { this->count_ = 0; } } extended_int(int64 that) { if (that > 0) { this->chunks_[0] = static_cast(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? 2 : 1; } else if (that < 0) { that = -that; this->chunks_[0] = static_cast(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? -2 : -1; } else { this->count_ = 0; } } extended_int(const std::vector& chunks, bool plus = true) { this->count_ = static_cast((std::min)(N, chunks.size())); for (int i = 0; i < this->count_; ++i) this->chunks_[i] = chunks[chunks.size() - i - 1]; if (!plus) this->count_ = -this->count_; } template extended_int(const extended_int& that) { this->count_ = that.count(); std::memcpy(this->chunks_, that.chunks(), that.size() * sizeof(uint32)); } extended_int& operator=(int32 that) { if (that > 0) { this->chunks_[0] = that; this->count_ = 1; } else if (that < 0) { this->chunks_[0] = -that; this->count_ = -1; } else { this->count_ = 0; } return *this; } extended_int& operator=(int64 that) { if (that > 0) { this->chunks_[0] = static_cast(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? 2 : 1; } else if (that < 0) { that = -that; this->chunks_[0] = static_cast(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? -2 : -1; } else { this->count_ = 0; } return *this; } template extended_int& operator=(const extended_int& that) { this->count_ = that.count(); std::memcpy(this->chunks_, that.chunks(), that.size() * sizeof(uint32)); return *this; } bool is_pos() const { return this->count_ > 0; } bool is_neg() const { return this->count_ < 0; } bool is_zero() const { return this->count_ == 0; } bool operator==(const extended_int& that) const { if (this->count_ != that.count()) return false; for (std::size_t i = 0; i < this->size(); ++i) if (this->chunks_[i] != that.chunks()[i]) return false; return true; } bool operator!=(const extended_int& that) const { return !(*this == that); } bool operator<(const extended_int& that) const { if (this->count_ != that.count()) return this->count_ < that.count(); std::size_t i = this->size(); if (!i) return false; do { --i; if (this->chunks_[i] != that.chunks()[i]) return (this->chunks_[i] < that.chunks()[i]) ^ (this->count_ < 0); } while (i); return false; } bool operator>(const extended_int& that) const { return that < *this; } bool operator<=(const extended_int& that) const { return !(that < *this); } bool operator>=(const extended_int& that) const { return !(*this < that); } extended_int operator-() const { extended_int ret_val = *this; ret_val.neg(); return ret_val; } void neg() { this->count_ = -this->count_; } extended_int operator+(const extended_int& that) const { extended_int ret_val; ret_val.add(*this, that); return ret_val; } void add(const extended_int& e1, const extended_int& e2) { if (!e1.count()) { *this = e2; return; } if (!e2.count()) { *this = e1; return; } if ((e1.count() > 0) ^ (e2.count() > 0)) { dif(e1.chunks(), e1.size(), e2.chunks(), e2.size()); } else { add(e1.chunks(), e1.size(), e2.chunks(), e2.size()); } if (e1.count() < 0) this->count_ = -this->count_; } extended_int operator-(const extended_int& that) const { extended_int ret_val; ret_val.dif(*this, that); return ret_val; } void dif(const extended_int& e1, const extended_int& e2) { if (!e1.count()) { *this = e2; this->count_ = -this->count_; return; } if (!e2.count()) { *this = e1; return; } if ((e1.count() > 0) ^ (e2.count() > 0)) { add(e1.chunks(), e1.size(), e2.chunks(), e2.size()); } else { dif(e1.chunks(), e1.size(), e2.chunks(), e2.size()); } if (e1.count() < 0) this->count_ = -this->count_; } extended_int operator*(int32 that) const { extended_int temp(that); return (*this) * temp; } extended_int operator*(int64 that) const { extended_int temp(that); return (*this) * temp; } extended_int operator*(const extended_int& that) const { extended_int ret_val; ret_val.mul(*this, that); return ret_val; } void mul(const extended_int& e1, const extended_int& e2) { if (!e1.count() || !e2.count()) { this->count_ = 0; return; } mul(e1.chunks(), e1.size(), e2.chunks(), e2.size()); if ((e1.count() > 0) ^ (e2.count() > 0)) this->count_ = -this->count_; } const uint32* chunks() const { return chunks_; } int32 count() const { return count_; } std::size_t size() const { return (std::abs)(count_); } std::pair p() const { std::pair ret_val(0, 0); std::size_t sz = this->size(); if (!sz) { return ret_val; } else { if (sz == 1) { ret_val.first = static_cast(this->chunks_[0]); } else if (sz == 2) { ret_val.first = static_cast(this->chunks_[1]) * static_cast(0x100000000LL) + static_cast(this->chunks_[0]); } else { for (std::size_t i = 1; i <= 3; ++i) { ret_val.first *= static_cast(0x100000000LL); ret_val.first += static_cast(this->chunks_[sz - i]); } ret_val.second = (sz - 3) << 5; } } if (this->count_ < 0) ret_val.first = -ret_val.first; return ret_val; } fpt64 d() const { std::pair p = this->p(); return std::ldexp(p.first, p.second); } private: void add(const uint32* c1, std::size_t sz1, const uint32* c2, std::size_t sz2) { if (sz1 < sz2) { add(c2, sz2, c1, sz1); return; } this->count_ = sz1; uint64 temp = 0; for (std::size_t i = 0; i < sz2; ++i) { temp += static_cast(c1[i]) + static_cast(c2[i]); this->chunks_[i] = static_cast(temp); temp >>= 32; } for (std::size_t i = sz2; i < sz1; ++i) { temp += static_cast(c1[i]); this->chunks_[i] = static_cast(temp); temp >>= 32; } if (temp && (this->count_ != N)) { this->chunks_[this->count_] = static_cast(temp); ++this->count_; } } void dif(const uint32* c1, std::size_t sz1, const uint32* c2, std::size_t sz2, bool rec = false) { if (sz1 < sz2) { dif(c2, sz2, c1, sz1, true); this->count_ = -this->count_; return; } else if ((sz1 == sz2) && !rec) { do { --sz1; if (c1[sz1] < c2[sz1]) { ++sz1; dif(c2, sz1, c1, sz1, true); this->count_ = -this->count_; return; } else if (c1[sz1] > c2[sz1]) { ++sz1; break; } } while (sz1); if (!sz1) { this->count_ = 0; return; } sz2 = sz1; } this->count_ = sz1-1; bool flag = false; for (std::size_t i = 0; i < sz2; ++i) { this->chunks_[i] = c1[i] - c2[i] - (flag?1:0); flag = (c1[i] < c2[i]) || ((c1[i] == c2[i]) && flag); } for (std::size_t i = sz2; i < sz1; ++i) { this->chunks_[i] = c1[i] - (flag?1:0); flag = !c1[i] && flag; } if (this->chunks_[this->count_]) ++this->count_; } void mul(const uint32* c1, std::size_t sz1, const uint32* c2, std::size_t sz2) { uint64 cur = 0, nxt, tmp; this->count_ = static_cast((std::min)(N, sz1 + sz2 - 1)); for (std::size_t shift = 0; shift < static_cast(this->count_); ++shift) { nxt = 0; for (std::size_t first = 0; first <= shift; ++first) { if (first >= sz1) break; std::size_t second = shift - first; if (second >= sz2) continue; tmp = static_cast(c1[first]) * static_cast(c2[second]); cur += static_cast(tmp); nxt += tmp >> 32; } this->chunks_[shift] = static_cast(cur); cur = nxt + (cur >> 32); } if (cur && (this->count_ != N)) { this->chunks_[this->count_] = static_cast(cur); ++this->count_; } } uint32 chunks_[N]; int32 count_; }; template bool is_pos(const extended_int& that) { return that.count() > 0; } template bool is_neg(const extended_int& that) { return that.count() < 0; } template bool is_zero(const extended_int& that) { return !that.count(); } struct type_converter_fpt { template fpt64 operator()(const T& that) const { return static_cast(that); } template fpt64 operator()(const extended_int& that) const { return that.d(); } fpt64 operator()(const extended_exponent_fpt& that) const { return that.d(); } }; struct type_converter_efpt { template extended_exponent_fpt operator()(const extended_int& that) const { std::pair p = that.p(); return extended_exponent_fpt(p.first, p.second); } }; // Voronoi coordinate type traits make it possible to extend algorithm // input coordinate range to any user provided integer type and algorithm // output coordinate range to any ieee-754 like floating point type. template struct voronoi_ctype_traits; template <> struct voronoi_ctype_traits { typedef int32 int_type; typedef int64 int_x2_type; typedef uint64 uint_x2_type; typedef extended_int<64> big_int_type; typedef fpt64 fpt_type; typedef extended_exponent_fpt efpt_type; typedef ulp_comparison ulp_cmp_type; typedef type_converter_fpt to_fpt_converter_type; typedef type_converter_efpt to_efpt_converter_type; }; } // detail } // polygon } // boost #endif // BOOST_POLYGON_DETAIL_VORONOI_CTYPES