carl  24.04
Computer ARithmetic Library
BVValue.cpp
Go to the documentation of this file.
1 #include "BVValue.h"
2 
3 namespace carl {
4 
5 BVValue::BVValue(std::size_t _width, const mpz_class& _value) {
6  // Obtain an mpz_t copy of _value
7  mpz_t value;
8  mpz_init(value);
9  mpz_set(value, _value.get_mpz_t());
10 
11  // Remember whether the given value is negative.
12  // The conversion is based on the mpz_export function, which ignores
13  // the sign. Hence, we have to construct the two's complement
14  // ourselves in case of negative numbers.
15  bool valueNegative = (mpz_sgn(value) == -1);
16 
17  if (valueNegative) {
18  // If the value is negative, increase it by 1 before conversion.
19  // This way we only have to flip all bits afterwards.
20  mpz_add_ui(value, value, 1);
21  }
22 
23  // We export into an array of Base::block_type.
24  // Calculate the number of needed blocks upfront
25  std::size_t bitsPerBlock = sizeof(Base::block_type) * CHAR_BIT;
26  std::size_t valueBits = mpz_sizeinbase(value, 2);
27  std::size_t blockCount = (valueBits + bitsPerBlock - 1) / bitsPerBlock;
28 
29  {
30  // The actual conversion from mpz_t to dynamic_bitset blocks
31  auto bits = std::make_unique<Base::block_type[]>(blockCount);
32  mpz_export(&bits[0], &blockCount, -1, sizeof(Base::block_type), -1, 0, value);
33 
34  // Import the blocks into mValue, and resize it afterwards to the desired size
35  mValue.append(&bits[0], &bits[0] + blockCount);
36  mValue.resize(_width);
37  }
38 
39  // If the value was negative, finalize the construction of the two's complement
40  // by inverting all bits
41  if (valueNegative) {
42  mValue.flip();
43  }
44 }
45 
46 BVValue BVValue::concat(const BVValue& _other) const {
47  Base concatenation(mValue);
48  concatenation.resize(width() + _other.width());
49  concatenation <<= _other.width();
50  Base otherResized = static_cast<Base>(_other);
51  otherResized.resize(concatenation.size());
52  concatenation |= otherResized;
53  return BVValue(std::move(concatenation));
54 }
55 
56 BVValue BVValue::divideSigned(const BVValue& _other) const {
57  assert(width() == _other.width());
58 
59  bool firstNegative = (*this)[width() - 1];
60  bool secondNegative = _other[_other.width() - 1];
61 
62  if (!firstNegative && !secondNegative) {
63  return (*this) / _other;
64  } else if (firstNegative && !secondNegative) {
65  return -(-(*this) / _other);
66  } else if (!firstNegative && secondNegative) {
67  return -((*this) / -_other);
68  } else {
69  return -(*this) / -_other;
70  }
71 }
72 
73 BVValue BVValue::remSigned(const BVValue& _other) const {
74  assert(width() == _other.width());
75 
76  bool firstNegative = (*this)[width() - 1];
77  bool secondNegative = _other[_other.width() - 1];
78 
79  if (!firstNegative && !secondNegative) {
80  return (*this) % _other;
81  } else if (firstNegative && !secondNegative) {
82  return -(-(*this) % _other);
83  } else if (!firstNegative && secondNegative) {
84  return (*this) % -_other;
85  } else {
86  return -((*this) % -_other);
87  }
88 }
89 
90 BVValue BVValue::modSigned(const BVValue& _other) const {
91  assert(width() == _other.width());
92 
93  bool firstNegative = (*this)[width() - 1];
94  bool secondNegative = _other[_other.width() - 1];
95 
96  BVValue absFirst(firstNegative ? -(*this) : (*this));
97  BVValue absSecond(secondNegative ? -_other : _other);
98 
99  BVValue u = absFirst % absSecond;
100 
101  if (u.is_zero()) {
102  return u;
103  } else if (!firstNegative && !secondNegative) {
104  return u;
105  } else if (firstNegative && !secondNegative) {
106  return -u + _other;
107  } else if (!firstNegative && secondNegative) {
108  return (*this) + _other;
109  } else {
110  return -u;
111  }
112 }
113 
114 BVValue BVValue::extract(std::size_t _highest, std::size_t _lowest) const {
115  assert(_highest < width() && _highest >= _lowest);
116  BVValue extraction(_highest - _lowest + 1);
117 
118  for (std::size_t i = 0; i < extraction.width(); ++i) {
119  extraction[i] = (*this)[_lowest + i];
120  }
121 
122  return extraction;
123 }
124 
125 BVValue BVValue::shift(const BVValue& _other, bool _left, bool _arithmetic) const {
126  std::size_t firstSize = width() - 1;
127  std::size_t highestRelevantPos = 0;
128 
129  bool fillWithOnes = !_left && _arithmetic && (*this)[width() - 1];
130 
131  while ((firstSize >>= 1) != 0)
132  ++highestRelevantPos;
133 
134  for (std::size_t i = highestRelevantPos + 1; i < _other.width(); ++i) {
135  if (_other[i]) {
136  Base allZero(width());
137  return BVValue(fillWithOnes ? ~allZero : allZero);
138  }
139  }
140 
141  Base shifted(fillWithOnes ? ~mValue : mValue);
142  std::size_t shiftBy = 1;
143 
144  for (std::size_t i = 0; i <= highestRelevantPos && i < _other.width(); ++i) {
145  if (_other[i]) {
146  if (_left) {
147  shifted <<= shiftBy;
148  } else {
149  shifted >>= shiftBy;
150  }
151  }
152  shiftBy *= 2;
153  }
154 
155  return BVValue(fillWithOnes ? ~shifted : shifted);
156 }
157 
158 BVValue BVValue::divideUnsigned(const BVValue& _other, bool _returnRemainder) const {
159  assert(width() == _other.width());
160  assert(Base(_other) != Base(_other.width(), 0));
161 
162  Base quotient(width());
163  std::size_t quotientIndex = 0;
164  Base divisor = static_cast<Base>(_other);
166 
167  while (!divisor[divisor.size() - 1] && remainder > divisor) {
168  ++quotientIndex;
169  divisor <<= 1;
170  }
171 
172  while (true) {
173  if (remainder >= divisor) {
174  quotient[quotientIndex] = true;
175  // substract divisor from remainder
176  bool carry = false;
177  for (std::size_t i = divisor.find_first(); i < remainder.size(); ++i) {
178  bool newRemainderI = (remainder[i] != divisor[i]) != carry;
179  carry = (remainder[i] && carry && divisor[i]) || (!remainder[i] && (carry || divisor[i]));
180  remainder[i] = newRemainderI;
181  }
182  }
183  if (quotientIndex == 0) {
184  break;
185  }
186  divisor >>= 1;
187  --quotientIndex;
188  }
189 
190  return BVValue(_returnRemainder ? std::move(remainder) : std::move(quotient));
191 }
192 
193 BVValue operator+(const BVValue& lhs, const BVValue& rhs) {
194  assert(lhs.width() == rhs.width());
195  bool carry = false;
196  BVValue::Base sum(lhs.width());
197  for (std::size_t i = 0; i < lhs.width(); ++i) {
198  sum[i] = (lhs[i] != rhs[i]) != carry;
199  carry = (lhs[i] && rhs[i]) || (carry && (lhs[i] || rhs[i]));
200  }
201  return BVValue(std::move(sum));
202 }
203 
204 BVValue operator*(const BVValue& lhs, const BVValue& rhs) {
205  assert(lhs.width() == rhs.width());
206  BVValue product(lhs.width());
207  BVValue::Base summand(lhs.base());
208 
209  for (std::size_t i = 0; i < lhs.width(); ++i) {
210  if (rhs[i]) {
211  product = product + BVValue(BVValue::Base(summand));
212  }
213  summand <<= 1;
214  }
215 
216  return product;
217 }
218 
219 }
carl is the main namespace for the library.
Interval< Number > operator+(const Interval< Number > &lhs, const Interval< Number > &rhs)
Operator for the addition of two intervals.
Definition: operators.h:261
Interval< Number > quotient(const Interval< Number > &_lhs, const Interval< Number > &_rhs)
Implements the division with remainder.
Definition: Interval.h:1488
Interval< Number > operator*(const Interval< Number > &lhs, const Interval< Number > &rhs)
Operator for the multiplication of two intervals.
Definition: operators.h:386
cln::cl_I remainder(const cln::cl_I &a, const cln::cl_I &b)
Calculate the remainder of the integer division.
Definition: operations.h:526
BVValue modSigned(const BVValue &_other) const
Definition: BVValue.cpp:90
BVValue extract(std::size_t _highest, std::size_t _lowest) const
Definition: BVValue.cpp:114
BVValue concat(const BVValue &_other) const
Definition: BVValue.cpp:46
BVValue divideUnsigned(const BVValue &_other, bool _returnRemainder=false) const
Definition: BVValue.cpp:158
std::size_t width() const
Definition: BVValue.h:68
BVValue()=default
BVValue shift(const BVValue &_other, bool _left, bool _arithmetic=false) const
Definition: BVValue.cpp:125
boost::dynamic_bitset< uint > Base
Definition: BVValue.h:19
Base mValue
Definition: BVValue.h:22
bool is_zero() const
Definition: BVValue.h:78
const Base & base() const
Definition: BVValue.h:64
BVValue divideSigned(const BVValue &_other) const
Definition: BVValue.cpp:56
BVValue remSigned(const BVValue &_other) const
Definition: BVValue.cpp:73