// ("Signed" here means two's-complement, just to be clear.)
#include "leading-zero-bit-count.h"
+#include "bit-population-count.h"
#include <cinttypes>
#include <climits>
#include <cstddef>
}
}
+ static constexpr FixedPoint HUGE() { return MASKR(bits-1); }
+
+ // Returns the number of full decimal digits that can be represented.
+ static constexpr int RANGE() {
+ if (bits < 4) {
+ return 0;
+ }
+ FixedPoint x{HUGE}, ten{std::uint64_t{10}};
+ int digits{0};
+ while (x.Compare(ten) != Ordering::Less) {
+ ++digits;
+ x = x.DivideUnsigned(ten).quotient;
+ }
+ return digits;
+ }
+
constexpr FixedPoint &operator=(const FixedPoint &) = default;
constexpr bool IsZero() const {
return bits;
}
- // POPCNT intrinsic
- // TODO pmk
- // pmk also POPPAR
+ // Count the number of bit positions that are set.
+ constexpr int POPCNT() const {
+ int count{0};
+ for (int j{0}; j < parts; ++j) {
+ count += BitPopulationCount(part_[j]);
+ }
+ return count;
+ }
+
+ // True when POPCNT is odd.
+ constexpr bool POPPAR() const { return POPCNT() & 1; }
+
+ constexpr int TRAILZ() const {
+ auto minus1{AddUnsigned(MASKR(bits))}; // { x-1, carry = x > 0 }
+ if (!minus1.carry) {
+ return bits; // was zero
+ } else {
+ // x ^ (x-1) has all bits set at and below original least-order set bit.
+ return POPCNT(IEOR(minus1.value)) - 1;
+ }
+ }
+
+ constexpr bool BTEST(int pos) const {
+ if (pos < 0 || pos >= bits) {
+ return false;
+ } else {
+ return (LEPart(pos / partBits) >> (pos % partBits)) & 1;
+ }
+ }
constexpr Ordering CompareUnsigned(const FixedPoint &y) const {
for (int j{parts}; j-- > 0;) {
return Ordering::Equal;
}
+ constexpr bool BGE(const FixedPoint &y) const {
+ return CompareUnsigned(y) != Ordering::Less;
+ }
+ constexpr bool BGT(const FixedPoint &y) const {
+ return CompareUnsigned(y) == Ordering::Greater;
+ }
+ constexpr bool BLE(const FixedPoint &y) const { return !BGT(y); }
+ constexpr bool BLT(const FixedPoint &y) const { return !BGE(y); }
+
constexpr Ordering CompareSigned(const FixedPoint &y) const {
bool isNegative{IsNegative()};
if (isNegative != y.IsNegative()) {
return {result, overflow};
}
+ constexpr ValueWithOverflow ABS() const {
+ if (IsNegative()) {
+ return Negate();
+ } else {
+ return {*this, false};
+ }
+ }
+
// Shifts the operand left when the count is positive, right when negative.
// Vacated bit positions are filled with zeroes.
constexpr FixedPoint ISHFT(int count) const {
}
}
- // TODO pmk
- // ISHFTC intrinsic - shift some least-significant bits circularly
- // DSHIFTL/R
+ // Circular shift of a field of least-significant bits. The least-order
+ // "size" bits are shifted circularly in place by "count" positions;
+ // the shift is leftward if count is nonnegative, rightward otherwise.
+ // Higher-order bits are unchanged.
+ constexpr FixedPoint ISHFTC(int count, int size) const {
+ if (count == 0 || size <= 0) {
+ return *this;
+ }
+ if (size > bits) {
+ size = bits;
+ }
+ if ((count %= size) == 0) {
+ return *this;
+ }
+ int middleBits, leastBits;
+ if (count > 0) {
+ middleBits = size - count;
+ leastBits = count;
+ } else {
+ middleBits = -count;
+ leastBits = size + count;
+ }
+ if (size == bits) {
+ return SHIFTL(leastBits).IOR(SHIFTR(middleBits));
+ }
+ FixedPoint unchanged{IAND(MASKL(bits - size))};
+ FixedPoint middle{IAND(MASKR(middleBits)).SHIFTL(leastBits)};
+ FixedPoint least{SHIFTR(middleBits).IAND(MASKR(leastBits))};
+ return unchanged.IOR(middle).IOR(least);
+ }
+
+ // Double shifts, aka shifts with specific fill
+ constexpr FixedPoint DSHIFTL(const FixedPoint &fill, int count) const {
+ if (count <= 0) {
+ return *this;
+ } else if (count >= 2 * bits) {
+ return {};
+ } else if (count > bits) {
+ return fill.SHIFTL(count - bits);
+ } else if (count == bits) {
+ return fill;
+ } else {
+ return SHIFTL(count).IOR(fill.SHIFTR(bits - count));
+ }
+ }
+
+ constexpr FixedPoint DSHIFTR(const FixedPoint &fill, int count) const {
+ if (count <= 0) {
+ return *this;
+ } else if (count >= 2 * bits) {
+ return {};
+ } else if (count > bits) {
+ return fill.SHIFTR(count - bits);
+ } else if (count == bits) {
+ return fill;
+ } else {
+ return SHIFTR(count).IOR(fill.SHIFTL(bits - count));
+ }
+ }
// Vacated upper bits are filled with zeroes.
constexpr FixedPoint SHIFTR(int count) const {
}
}
+ // Clears a single bit.
+ constexpr FixedPoint IBCLR(int pos) const {
+ if (pos < 0 || pos >= bits) {
+ return *this;
+ } else {
+ FixedPoint result{*this};
+ result.LEPart(pos / partBits) &= ~(Part{1} << (pos % partBits));
+ return result;
+ }
+ }
+
+ // Sets a single bit.
+ constexpr FixedPoint IBSET(int pos) const {
+ if (pos < 0 || pos >= bits) {
+ return *this;
+ } else {
+ FixedPoint result{*this};
+ result.LEPart(pos / partBits) |= Part{1} << (pos % partBits);
+ return result;
+ }
+ }
+
+ // Extracts a field.
+ constexpr FixedPoint IBITS(int pos, int size) const {
+ return SHIFTR(pos).IAND(MASKR(size));
+ }
+
constexpr FixedPoint IAND(const FixedPoint &y) const {
FixedPoint result{nullptr};
for (int j{0}; j < parts; ++j) {
return result;
}
+ constexpr FixedPoint MERGE_BITS(const FixedPoint &y,
+ const FixedPoint &mask) const {
+ return IAND(mask).IOR(y.IAND(mask.NOT()));
+ }
+
+ constexpr FixedPoint MAX(const FixedPoint &y) const {
+ if (CompareSigned(y) == Ordering::Less) {
+ return y;
+ } else {
+ return *this;
+ }
+ }
+
+ constexpr FixedPoint MIN(const FixedPoint &y) const {
+ if (CompareSigned(y) == Ordering::Less) {
+ return *this;
+ } else {
+ return y;
+ }
+ }
+
// Unsigned addition with carry.
struct ValueWithCarry {
FixedPoint value;
return {diff.value, overflow};
}
+ // MAX(X-Y, 0)
+ constexpr FixedPoint DIM(const FixedPoint &y) const {
+ if (CompareSigned(y) != Ordering::Greater) {
+ return {};
+ } else {
+ return SubtractSigned(y).value;
+ }
+ }
+
+ constexpr ValueWithOverflow SIGN(const FixedPoint &sign) const {
+ bool goNegative{sign.IsNegative()};
+ if (goNegative == IsNegative()) {
+ return *this;
+ } else if (goNegative) {
+ return Negate();
+ } else {
+ return ABS();
+ }
+ }
+
struct Product {
FixedPoint upper, lower;
};
std::uint64_t lzcheck{std::uint64_t{1} << (BITS - lzbc)};
COMPARE(x, <, lzcheck)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
COMPARE(x + x + !x, >=, lzcheck)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
+ int popcheck{0};
+ for (int j{0}; j < BITS; ++j) {
+ popcheck += (x >> j) & 1;
+ }
+ MATCH(popcheck, a.POPCNT())("%s, x=0x%llx", desc, x);
+ MATCH(popcheck & 1, a.POPPAR())("%s, x=0x%llx", desc, x);
Ordering ord{Ordering::Equal};
std::int64_t sx = x;
if (x + x > maxUnsignedValue) {
MATCH(sx - sy * (sx / sy), quot.remainder.ToInt64())
("%s, x=0x%llx, y=0x%llx", desc, x, y);
}
- // TODO test MODULO
+ // TODO test ABS, B[GL][ET], BTEST, DIM, HUGE, MODULO, ISHFTC, DSHIFTL/R
+ // TODO test IBCLR, IBSET, IBITS, MAX, MIN, MERGE_BITS, RANGE, SIGN
+ // TODO test TRAILZ
}
}
}