more work on src/util, mainly on the bitset class

This commit is contained in:
lperron@google.com
2014-04-04 09:13:02 +00:00
parent 3c15315a8b
commit a9dcc289d6
3 changed files with 73 additions and 4 deletions

View File

@@ -30,6 +30,7 @@ namespace operations_research {
// Useful constants: word and double word will all bits set.
static const uint64 kAllBits64 = GG_ULONGLONG(0xFFFFFFFFFFFFFFFF);
static const uint64 kAllBitsButLsb64 = GG_ULONGLONG(0xFFFFFFFFFFFFFFFE);
static const uint32 kAllBits32 = 0xFFFFFFFFU;
// Returns a word with only bit pos set.
@@ -426,6 +427,11 @@ class Bitset64 {
memset(data_.data(), 0, to_clear * sizeof(int64));
}
// Sets all bits to 0.
void ClearAll() {
memset(data_.data(), 0, data_.size() * sizeof(int64));
}
// Sets the bit at position i to 0.
void Clear(IndexType i) {
DCHECK_GE(Value(i), 0);
@@ -433,6 +439,13 @@ class Bitset64 {
data_[BitOffset64(Value(i))] &= ~OneBit64(BitPos64(Value(i)));
}
// Sets bucket containing bit i to 0.
void ClearBucket(IndexType i) {
DCHECK_GE(Value(i), 0);
DCHECK_LT(Value(i), size_);
data_[BitOffset64(Value(i))] = 0;
}
// Copies the bits at position i and i ^ 1 and then clear them.
void CopyAndClearTwoBits(IndexType i, Bitset64* to) {
DCHECK_GE(Value(i), 0);
@@ -476,6 +489,35 @@ class Bitset64 {
}
}
// Copies bucket containing bit i from "other" to "this".
void CopyBucket(const Bitset64<IndexType>& other, IndexType i) {
const uint64 offset = BitOffset64(Value(i));
data_[offset] = other.data_[offset];
}
// Copies "other" to "this". The bitsets do not have to be of the same size.
// If "other" is smaller, high order bits are not changed. If "other" is
// larger, its high order bits are ignored. In any case "this" is not resized.
void SetContentFromBitset(const Bitset64<IndexType>& other) {
const int min_size = std::min(data_.size(), other.data_.size());
if (min_size == 0) return;
const uint64 last_common_bucket = data_[min_size - 1];
memcpy(data_.data(), other.data_.data(), min_size * sizeof(uint64));
if (data_.size() >= other.data_.size()) {
const uint64 bitmask =
kAllBitsButLsb64 << BitPos64(Value(other.size() - 1));
data_[min_size - 1] &= ~bitmask;
data_[min_size - 1] |= (bitmask & last_common_bucket);
}
}
// Same as SetContentFromBitset where "this" and "other" have the same size.
void SetContentFromBitsetOfSameSize(const Bitset64<IndexType>& other) {
DCHECK_EQ(size(), other.size());
memcpy(data_.data(), other.data_.data(), data_.size() * sizeof(uint64));
}
// Sets "this" to be the intersection of "this" and "other". The
// bitsets do not have to be the same size. If other is smaller, all
// the higher order bits are assumed to be 0.
@@ -585,6 +627,15 @@ class Bitset64 {
((use2 << pos) & other2.data_[bucket]);
}
// Returns a 0/1 std::string representing the bitset.
std::string DebugString() const {
std::string output;
for (IndexType i(0); i < size(); ++i) {
output += IsSet(i) ? "1" : "0";
}
return output;
}
private:
// Returns the value of the index type.
// This function is specialized below to work with IntType and int64.
@@ -620,16 +671,24 @@ class SparseBitset {
SparseBitset() {}
explicit SparseBitset(IntegerType size) : bitset_(size) {}
IntegerType size() const { return bitset_.size(); }
void SparseClearAll() {
for (const IntegerType i : to_clear_) bitset_.ClearBucket(i);
to_clear_.clear();
}
void ClearAll() {
bitset_.ClearAll();
to_clear_.clear();
}
void ClearAndResize(IntegerType size) {
// As of 19/03/2014, experiments show that this is a reasonable threshold.
const int kSparseThreshold = 300;
if (to_clear_.size() * kSparseThreshold < size) {
for (const IntegerType i : to_clear_) Clear(i);
SparseClearAll();
bitset_.Resize(size);
} else {
bitset_.ClearAndResize(size);
to_clear_.clear();
}
to_clear_.clear();
}
bool operator[](IntegerType index) const { return bitset_[index]; }
void Set(IntegerType index) {

View File

@@ -165,6 +165,13 @@ void GetBestScalingOfDoublesToInt64(const std::vector<double>& x,
double* scaling_factor,
double* relative_error);
// Returns the Greatest Common Divisor of the numbers
// round(fabs(x[i] * scaling_factor)). The numbers 0 are ignored and if they are
// all zero then the result is 1. Note that round(fabs()) is the same as
// fabs(round()) since the numbers are rounded away from zero.
int64 ComputeGcdOfRoundedDoubles(const std::vector<double>& x,
double scaling_factor);
} // namespace operations_research
#endif // OR_TOOLS_UTIL_FP_UTILS_H_

View File

@@ -21,12 +21,15 @@ namespace operations_research {
// ---------- Overflow utility functions ----------
// Performs *b += a and returns false iff the addition overflow or underflow.
// This function only works for typed integer type (IntType<>).
template <typename IntegerType>
bool SafeAddInto(IntegerType a, IntegerType* b) {
if (a > 0) {
if (*b > std::numeric_limits<IntegerType>::max() - a) return false;
if (*b > std::numeric_limits<typename IntegerType::ValueType>::max() - a)
return false;
} else {
if (*b < std::numeric_limits<IntegerType>::min() - a) return false;
if (*b < std::numeric_limits<typename IntegerType::ValueType>::min() - a)
return false;
}
*b += a;
return true;