GteUIntegerALU32.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
11 #include <algorithm>
12 
13 // Support for unsigned integer arithmetic in BSNumber and BSRational. The
14 // Curiously Recurring Template Paradigm is used to allow the UInteger
15 // types to share code without introducing virtual functions.
16 
17 namespace gte
18 {
19 
20 template <typename UInteger>
22 {
23 public:
24  // Comparisons. These are not generic. They rely on their being caled
25  // when the two BSNumber arguments to BSNumber::operatorX() are of the
26  // form 1.u*2^p and 1.v*2^p. The comparisons apply to 1.u and 1.v as
27  // unsigned integers with their leading 1-bits aligned.
28  bool operator==(UInteger const& number) const;
29  bool operator!=(UInteger const& number) const;
30  bool operator< (UInteger const& number) const;
31  bool operator<=(UInteger const& number) const;
32  bool operator> (UInteger const& number) const;
33  bool operator>=(UInteger const& number) const;
34 
35  // Arithmetic operations. These are performed in-place; that is, the
36  // result is stored in 'this' object. The goal is to reduce the number of
37  // object copies, much like the goal is for std::move. The Sub function
38  // requires the inputs to satisfy n0 > n1.
39  void Add(UInteger const& n0, UInteger const& n1);
40  void Sub(UInteger const& n0, UInteger const& n1);
41  void Mul(UInteger const& n0, UInteger const& n1);
42 
43  // The shift is performed in-place; that is, the result is stored in
44  // 'this' object.
45  void ShiftLeft(UInteger const& number, int32_t shift);
46 
47  // The 'number' is even and positive. It is shifted right to become an
48  // odd number and the return value is the amount shifted. The operation
49  // is performed in-place; that is, the result is stored in 'this' object.
50  int32_t ShiftRightToOdd(UInteger const& number);
51 
52  // Get a block of numRequested bits starting with the leading 1-bit of the
53  // nonzero number. The returned number has the prefix stored in the
54  // high-order bits. Additional bits are copied and used by the caller for
55  // rounding. This function supports conversions from 'float' and 'double'.
56  // The input 'numRequested' is smaller than 64.
57  uint64_t GetPrefix(int32_t numRequested) const;
58 };
59 
60 
61 template <typename UInteger>
62 bool UIntegerALU32<UInteger>::operator==(UInteger const& number) const
63 {
64  UInteger const& self = *(UInteger const*)this;
65  int32_t numBits = self.GetNumBits();
66  if (numBits != number.GetNumBits())
67  {
68  return false;
69  }
70 
71  if (numBits > 0)
72  {
73  auto const& bits = self.GetBits();
74  auto const& nBits = number.GetBits();
75  int32_t const last = self.GetSize() - 1;
76  for (int32_t i = last; i >= 0; --i)
77  {
78  if (bits[i] != nBits[i])
79  {
80  return false;
81  }
82  }
83  }
84  return true;
85 }
86 
87 template <typename UInteger>
88 bool UIntegerALU32<UInteger>::operator!=(UInteger const& number) const
89 {
90  return !operator==(number);
91 }
92 
93 template <typename UInteger>
94 bool UIntegerALU32<UInteger>::operator< (UInteger const& number) const
95 {
96  UInteger const& self = *(UInteger const*)this;
97  int32_t nNumBits = number.GetNumBits();
98  auto const& nBits = number.GetBits();
99 
100  int32_t numBits = self.GetNumBits();
101  if (numBits > 0 && nNumBits > 0)
102  {
103  // The numbers must be compared as if they are left-aligned with
104  // each other. We got here because we had self = 1.u * 2^p and
105  // number = 1.v * 2^p. Although they have the same exponent, it is
106  // possible that 'self < number' but 'numBits(1u) > numBits(1v)'.
107  // Compare the bits one 32-bit block at a time.
108  auto const& bits = self.GetBits();
109  int bitIndex0 = numBits - 1;
110  int bitIndex1 = nNumBits - 1;
111  int block0 = bitIndex0 / 32;
112  int block1 = bitIndex1 / 32;
113  int numBlockBits0 = 1 + (bitIndex0 % 32);
114  int numBlockBits1 = 1 + (bitIndex1 % 32);
115  uint64_t n0shift = bits[block0];
116  uint64_t n1shift = nBits[block1];
117  while (block0 >= 0 && block1 >= 0)
118  {
119  // Shift the bits in the leading blocks to the high-order bit.
120  uint32_t value0 =
121  GTE_GET_LO_U64(n0shift << (32 - numBlockBits0));
122  uint32_t value1 =
123  GTE_GET_LO_U64(n1shift << (32 - numBlockBits1));
124 
125  // Shift bits in the next block (if any) to fill the current
126  // block.
127  if (--block0 >= 0)
128  {
129  n0shift = bits[block0];
130  value0 |= GTE_GET_LO_U64(n0shift >> numBlockBits0);
131  }
132  if (--block1 >= 0)
133  {
134  n1shift = nBits[block1];
135  value1 |= GTE_GET_LO_U64(n1shift >> numBlockBits1);
136  }
137  if (value0 < value1)
138  {
139  return true;
140  }
141  if (value0 > value1)
142  {
143  return false;
144  }
145  }
146  return block0 < block1;
147  }
148  else
149  {
150  // One or both numbers are negative. The only time 'less than' is
151  // 'true' is when 'number' is positive.
152  return (nNumBits > 0);
153  }
154 }
155 
156 template <typename UInteger>
157 bool UIntegerALU32<UInteger>::operator<=(UInteger const& number) const
158 {
159  return operator<(number) || operator==(number);
160 }
161 
162 template <typename UInteger>
163 bool UIntegerALU32<UInteger>::operator> (UInteger const& number) const
164 {
165  return !operator<=(number);
166 }
167 
168 template <typename UInteger>
169 bool UIntegerALU32<UInteger>::operator>=(UInteger const& number) const
170 {
171  return !operator<(number);
172 }
173 
174 template <typename UInteger>
175 void UIntegerALU32<UInteger>::Add(UInteger const& n0, UInteger const& n1)
176 {
177  UInteger& self = *(UInteger*)this;
178  int32_t n0NumBits = n0.GetNumBits();
179  int32_t n1NumBits = n1.GetNumBits();
180 
181  // Add the numbers considered as positive integers. Set the last block to
182  // zero in case no carry-out occurs.
183  int numBits = std::max(n0NumBits, n1NumBits) + 1;
184  self.SetNumBits(numBits);
185  self.SetBack(0);
186 
187  // Get the input array sizes.
188  int32_t numElements0 = n0.GetSize();
189  int32_t numElements1 = n1.GetSize();
190 
191  // Order the inputs so that the first has the most blocks.
192  auto const& u0 =
193  (numElements0 >= numElements1 ? n0.GetBits() : n1.GetBits());
194  auto const& u1 =
195  (numElements0 >= numElements1 ? n1.GetBits() : n0.GetBits());
196  auto numElements = std::minmax(numElements0, numElements1);
197 
198  // Add the u1-blocks to u0-blocks.
199  auto& bits = self.GetBits();
200  uint64_t carry = 0, sum;
201  int32_t i;
202  for (i = 0; i < numElements.first; ++i)
203  {
204  sum = u0[i] + (u1[i] + carry);
205  bits[i] = GTE_GET_LO_U64(sum);
206  carry = (sum >> 32);
207  }
208 
209  // We have no more u1-blocks. Propagate the carry-out, if there is one, or
210  // copy the remaining blocks if there is not.
211  if (carry > 0)
212  {
213  for (; i < numElements.second; ++i)
214  {
215  sum = u0[i] + carry;
216  bits[i] = GTE_GET_LO_U64(sum);
217  carry = (sum >> 32);
218  }
219  if (carry > 0)
220  {
221  bits[i] = GTE_GET_LO_U64(carry);
222  }
223  }
224  else
225  {
226  for (; i < numElements.second; ++i)
227  {
228  bits[i] = u0[i];
229  }
230  }
231 
232  // Reduce the number of bits if there was not a carry-out.
233  uint32_t firstBitIndex = (numBits - 1) % 32;
234  uint32_t mask = (1 << firstBitIndex);
235  if ((mask & self.GetBack()) == 0)
236  {
237  self.SetNumBits(--numBits);
238  }
239 }
240 
241 template <typename UInteger>
242 void UIntegerALU32<UInteger>::Sub(UInteger const& n0, UInteger const& n1)
243 {
244  UInteger& self = *(UInteger*)this;
245  int32_t n0NumBits = n0.GetNumBits();
246  auto const& n0Bits = n0.GetBits();
247  auto const& n1Bits = n1.GetBits();
248 
249  // Subtract the numbers considered as positive integers. We know that
250  // n0 > n1, so create a number n2 that has the same number of bits as
251  // n0 and use two's-complement to generate -n2, and then add n0 and -n2.
252  // The result is nonnegative, so we do not need to apply two's complement
253  // to a negative result to extract the sign and absolute value.
254 
255  // Get the input array sizes. We know numElements0 >= numElements1.
256  int32_t numElements0 = n0.GetSize();
257  int32_t numElements1 = n1.GetSize();
258 
259  // Create the two's-complement number n2. We know n2.GetNumElements() is
260  // the same as numElements0.
261  UInteger n2(n0NumBits);
262  auto& n2Bits = n2.GetBits();
263  int32_t i;
264  for (i = 0; i < numElements1; ++i)
265  {
266  n2Bits[i] = ~n1Bits[i];
267  }
268  for (; i < numElements0; ++i)
269  {
270  n2Bits[i] = ~0u;
271  }
272 
273  // Now add 1 to the bit-negated result to obtain -n1.
274  uint64_t carry = 1, sum;
275  for (i = 0; i < numElements0; ++i)
276  {
277  sum = n2Bits[i] + carry;
278  n2Bits[i] = GTE_GET_LO_U64(sum);
279  carry = (sum >> 32);
280  }
281 
282  // Add the numbers as positive integers. Set the last block to zero in
283  // case no carry-out occurs.
284  self.SetNumBits(n0NumBits + 1);
285  self.SetBack(0);
286 
287  // Add the n0-blocks to n2-blocks.
288  auto& bits = self.GetBits();
289  for (i = 0, carry = 0; i < numElements0; ++i)
290  {
291  sum = n2Bits[i] + (n0Bits[i] + carry);
292  bits[i] = GTE_GET_LO_U64(sum);
293  carry = (sum >> 32);
294  }
295 
296  // Strip off the bits introduced by two's-complement.
297  int32_t block;
298  for (block = numElements0 - 1; block >= 0; --block)
299  {
300  if (bits[block] > 0)
301  {
302  break;
303  }
304  }
305 
306  self.SetNumBits(32 * block + GetLeadingBit(bits[block]) + 1);
307 }
308 
309 template <typename UInteger>
310 void UIntegerALU32<UInteger>::Mul(UInteger const& n0, UInteger const& n1)
311 {
312  UInteger& self = *(UInteger*)this;
313  int32_t n0NumBits = n0.GetNumBits();
314  int32_t n1NumBits = n1.GetNumBits();
315  auto const& n0Bits = n0.GetBits();
316  auto const& n1Bits = n1.GetBits();
317 
318  // The number of bits is at most this, possibly one bit smaller.
319  int numBits = n0NumBits + n1NumBits;
320  self.SetNumBits(numBits);
321  auto& bits = self.GetBits();
322 
323  // Product of a single-block number with a multiple-block number.
324  UInteger product(numBits);
325  auto& pBits = product.GetBits();
326 
327  // Get the array sizes.
328  int32_t const numElements0 = n0.GetSize();
329  int32_t const numElements1 = n1.GetSize();
330  int32_t const numElements = self.GetSize();
331 
332  // Compute the product v = u0*u1.
333  int32_t i0, i1, i2;
334  uint64_t term, sum;
335 
336  // The case i0 == 0 is handled separately to initialize the accumulator
337  // with u0[0]*v. This avoids having to fill the bytes of 'bits' with
338  // zeros outside the double loop, something that can be a performance
339  // issue when 'numBits' is large.
340  uint64_t block0 = n0Bits[0];
341  uint64_t carry = 0;
342  for (i1 = 0; i1 < numElements1; ++i1)
343  {
344  term = block0 * n1Bits[i1] + carry;
345  bits[i1] = GTE_GET_LO_U64(term);
346  carry = (term >> 32);
347  }
348  if (i1 < numElements)
349  {
350  bits[i1] = GTE_GET_LO_U64(carry);
351  }
352 
353  for (i0 = 1; i0 < numElements0; ++i0)
354  {
355  // Compute the product p = u0[i0]*u1.
356  block0 = n0Bits[i0];
357  carry = 0;
358  for (i1 = 0, i2 = i0; i1 < numElements1; ++i1, ++i2)
359  {
360  term = block0 * n1Bits[i1] + carry;
361  pBits[i2] = GTE_GET_LO_U64(term);
362  carry = (term >> 32);
363  }
364  if (i2 < numElements)
365  {
366  pBits[i2] = GTE_GET_LO_U64(carry);
367  }
368 
369  // Add p to the accumulator v.
370  carry = 0;
371  for (i1 = 0, i2 = i0; i1 < numElements1; ++i1, ++i2)
372  {
373  sum = pBits[i2] + (bits[i2] + carry);
374  bits[i2] = GTE_GET_LO_U64(sum);
375  carry = (sum >> 32);
376  }
377  if (i2 < numElements)
378  {
379  sum = pBits[i2] + carry;
380  bits[i2] = GTE_GET_LO_U64(sum);
381  }
382  }
383 
384  // Reduce the number of bits if there was not a carry-out.
385  uint32_t firstBitIndex = (numBits - 1) % 32;
386  uint32_t mask = (1 << firstBitIndex);
387  if ((mask & self.GetBack()) == 0)
388  {
389  self.SetNumBits(--numBits);
390  }
391 }
392 
393 template <typename UInteger>
394 void UIntegerALU32<UInteger>::ShiftLeft(UInteger const& number, int32_t shift)
395 {
396  UInteger& self = *(UInteger*)this;
397  int32_t nNumBits = number.GetNumBits();
398  auto const& nBits = number.GetBits();
399 
400  // Shift the 'number' considered as an odd positive integer.
401  self.SetNumBits(nNumBits + shift);
402 
403  // Set the low-order bits to zero.
404  auto& bits = self.GetBits();
405  int32_t const shiftBlock = shift / 32;
406  for (int32_t i = 0; i < shiftBlock; ++i)
407  {
408  bits[i] = 0;
409  }
410 
411  // Get the location of the low-order 1-bit within the result.
412  int32_t const numInElements = number.GetSize();
413  int32_t const lshift = shift % 32;
414  int32_t i, j;
415  if (lshift > 0)
416  {
417  // The trailing 1-bits for source and target are at different
418  // relative indices. Each shifted source block straddles a boundary
419  // between two target blocks, so we must extract the subblocks and
420  // copy accordingly.
421  int32_t const rshift = 32 - lshift;
422  uint32_t prev = 0, curr;
423  for (i = shiftBlock, j = 0; j < numInElements; ++i, ++j)
424  {
425  curr = nBits[j];
426  bits[i] = (curr << lshift) | (prev >> rshift);
427  prev = curr;
428  }
429  if (i < self.GetSize())
430  {
431  // The leading 1-bit of the source is at a relative index such
432  // that when you add the shift amount, that bit occurs in a new
433  // block.
434  bits[i] = (prev >> rshift);
435  }
436  }
437  else
438  {
439  // The trailing 1-bits for source and target are at the same relative
440  // index. The shift reduces to a block copy.
441  for (i = shiftBlock, j = 0; j < numInElements; ++i, ++j)
442  {
443  bits[i] = nBits[j];
444  }
445  }
446 }
447 
448 template <typename UInteger>
449 int32_t UIntegerALU32<UInteger>::ShiftRightToOdd(UInteger const& number)
450 {
451  UInteger& self = *(UInteger*)this;
452  auto const& nBits = number.GetBits();
453 
454  // Get the leading 1-bit.
455  int32_t const numElements = number.GetSize();
456  int32_t const numM1 = numElements - 1;
457  int32_t firstBitIndex = 32 * numM1 + GetLeadingBit(nBits[numM1]);
458 
459  // Get the trailing 1-bit.
460  int32_t lastBitIndex = -1;
461  for (int32_t block = 0; block < numElements; ++block)
462  {
463  uint32_t value = nBits[block];
464  if (value > 0)
465  {
466  lastBitIndex = 32 * block + GetTrailingBit(value);
467  break;
468  }
469  }
470 
471  // The right-shifted result.
472  self.SetNumBits(firstBitIndex - lastBitIndex + 1);
473  auto& bits = self.GetBits();
474  int32_t const numBlocks = self.GetSize();
475 
476  // Get the location of the low-order 1-bit within the result.
477  int32_t const shiftBlock = lastBitIndex / 32;
478  int32_t rshift = lastBitIndex % 32;
479  if (rshift > 0)
480  {
481  int32_t const lshift = 32 - rshift;
482  int32_t i, j = shiftBlock;
483  uint32_t curr = nBits[j++];
484  for (i = 0; j < numElements; ++i, ++j)
485  {
486  uint32_t next = nBits[j];
487  bits[i] = (curr >> rshift) | (next << lshift);
488  curr = next;
489  }
490  if (i < numBlocks)
491  {
492  bits[i] = (curr >> rshift);
493  }
494  }
495  else
496  {
497  for (int32_t i = 0, j = shiftBlock; i < numBlocks; ++i, ++j)
498  {
499  bits[i] = nBits[j];
500  }
501  }
502 
503  return rshift + 32 * shiftBlock;
504 }
505 
506 template <typename UInteger>
507 uint64_t UIntegerALU32<UInteger>::GetPrefix(int32_t numRequested) const
508 {
509  UInteger const& self = *(UInteger const*)this;
510  auto const& bits = self.GetBits();
511 
512  // Copy to 'prefix' the leading 32-bit block that is nonzero.
513  int32_t bitIndex = self.GetNumBits() - 1;
514  int32_t blockIndex = bitIndex / 32;
515  uint64_t prefix = bits[blockIndex];
516 
517  // Get the number of bits in the block starting with the leading 1-bit.
518  int32_t firstBitIndex = bitIndex % 32;
519  int32_t numBlockBits = firstBitIndex + 1;
520 
521  // Shift the leading 1-bit to bit-63 of prefix. We have consumed
522  // numBlockBits, which might not be the entire budget.
523  int32_t targetIndex = 63;
524  prefix <<= targetIndex - firstBitIndex;
525  numRequested -= numBlockBits;
526  targetIndex -= numBlockBits;
527 
528  if (numRequested > 0 && --blockIndex >= 0)
529  {
530  // More bits are available. Copy and shift the entire 32-bit next
531  // block and OR it into the 'prefix'. For 'float', we will have
532  // consumed the entire budget. For 'double', we might have to get
533  // bits from a third block.
534  uint64_t nextBlock = bits[blockIndex];
535  nextBlock <<= targetIndex - 31; // Shift amount is positive.
536  prefix |= nextBlock;
537  numRequested -= 32;
538  targetIndex -= 32;
539 
540  if (numRequested > 0 && --blockIndex >= 0)
541  {
542  // We know that targetIndex > 0; only 'double' allows us to get
543  // here, so numRequested is at most 53. We also know that
544  // targetIndex < 32 because we started with 63 and subtracted
545  // at least 32 from it. Thus, the shift amount is positive.
546  nextBlock = bits[blockIndex];
547  nextBlock >>= 31 - targetIndex;
548  prefix |= nextBlock;
549  }
550  }
551 
552  return prefix;
553 }
554 
555 
556 }
uint64_t GetPrefix(int32_t numRequested) const
GTE_IMPEXP int32_t GetTrailingBit(uint32_t value)
GLfixed u1
Definition: glext.h:4927
bool operator==(UInteger const &number) const
GTE_IMPEXP int32_t GetLeadingBit(uint32_t value)
Definition: GteBitHacks.cpp:61
int32_t ShiftRightToOdd(UInteger const &number)
GLsizei const GLfloat * value
Definition: glcorearb.h:819
GLint GLuint mask
Definition: glcorearb.h:119
void ShiftLeft(UInteger const &number, int32_t shift)
bool operator!=(UInteger const &number) const
void Sub(UInteger const &n0, UInteger const &n1)
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
Definition: glext.h:6545
#define GTE_GET_LO_U64(v)
Definition: GteBitHacks.h:18
bool operator>=(UInteger const &number) const
void Add(UInteger const &n0, UInteger const &n1)
bool operator>(UInteger const &number) const
void Mul(UInteger const &n0, UInteger const &n1)
bool operator<=(UInteger const &number) const
bool operator<(UInteger const &number) const


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:01