-
Notifications
You must be signed in to change notification settings - Fork 12
Implement Exponentiation via Associative Iteration #75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 6 commits
530543a
c600842
3b9f000
07952f5
bc27994
264dce9
9943917
acdaa6f
4eace36
88360cf
4801e56
582affe
78be7f7
48f9604
bee7202
332bd67
a2e30d6
7d8379f
20e7f42
bf2be04
3af74ee
c83ac4a
4261a23
f665142
cb496ca
449de1f
756a5ee
0d8fa58
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,7 +69,7 @@ template<int NB, typename B> | |
constexpr auto makeLaneMaskFromMSB(SWAR<NB, B> input) { | ||
using S = SWAR<NB, B>; | ||
auto msb = input & S{S::MostSignificantBit}; | ||
auto msbCopiedToLSB = S{msb.value() >> (NB - 1)}; | ||
auto msbCopiedToLSB = S{static_cast<B>(msb.value() >> (NB - 1))}; | ||
return impl::makeLaneMaskFromMSB_and_LSB(msb, msbCopiedToLSB); | ||
} | ||
|
||
|
@@ -218,16 +218,69 @@ constexpr auto multiplication_OverflowUnsafe_SpecificBitCount( | |
|
||
auto halver = [](auto counts) { | ||
auto msbCleared = counts & ~S{S::MostSignificantBit}; | ||
return S{msbCleared.value() << 1}; | ||
return S{static_cast<T>(msbCleared.value() << 1)}; | ||
}; | ||
|
||
multiplier = S{multiplier.value() << (NB - ActualBits)}; | ||
multiplier = S{static_cast<T>(multiplier.value() << (NB - ActualBits))}; | ||
return associativeOperatorIterated_regressive( | ||
multiplicand, S{0}, multiplier, S{S::MostSignificantBit}, operation, | ||
ActualBits, halver | ||
); | ||
} | ||
|
||
|
||
/* | ||
// extended from mathematics to generic programming | ||
// see https://github.com/jamierpond/fmtgp/blob/main/2_first_algo/main.cpp | ||
|
||
template <typename T> constexpr T exp_acc(T r, T a, T n) { | ||
for (;;) { | ||
if (is_odd(n)) { | ||
r = multiply(r, a); | ||
if (n == 1) { | ||
return r; | ||
} | ||
} | ||
n = half(n); | ||
a = multiply(a, a); | ||
} | ||
} | ||
*/ | ||
|
||
template<int ActualBits, int NB, typename T> | ||
constexpr auto expo_OverflowUnsafe_SpecificBitCount( | ||
jamierpond marked this conversation as resolved.
Show resolved
Hide resolved
|
||
SWAR<NB, T> x, | ||
SWAR<NB, T> exponent | ||
) { | ||
using S = SWAR<NB, T>; | ||
|
||
auto operation = [](auto left, auto right, auto counts) { | ||
const auto mask = makeLaneMaskFromMSB(counts); | ||
const auto antiMask = ~mask; | ||
const auto product = | ||
multiplication_OverflowUnsafe_SpecificBitCount<ActualBits>(left, right); | ||
/* | ||
* if (count) | ||
* return product; | ||
* else | ||
* return left; | ||
*/ | ||
return (product & mask) | (left & antiMask); | ||
}; | ||
|
||
// halver should work same as multiplication... i think... | ||
auto halver = [](auto counts) { | ||
auto msbCleared = counts & ~S{S::MostSignificantBit}; | ||
return S{static_cast<T>(msbCleared.value() << 1)}; | ||
jamierpond marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
exponent = S{static_cast<T>(exponent.value() << (NB - ActualBits))}; | ||
return associativeOperatorIterated_regressive( | ||
x, S{1}, exponent, S{S::MostSignificantBit}, operation, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your neutral is, lane wise, { 0, ..., 1 }, so, the upper lanes are initialized to 0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ooh thanks for that, that makes total sense! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possibly, but using BitmaskMaker can be upgraded to support longer types. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is, indeed, subtle. Perhaps not so subtle in the SIMD |
||
ActualBits, halver | ||
); | ||
} | ||
|
||
/// \note Not removed yet because it is an example of "progressive" associative exponentiation | ||
template<int ActualBits, int NB, typename T> | ||
constexpr auto multiplication_OverflowUnsafe_SpecificBitCount_deprecated( | ||
|
@@ -261,6 +314,17 @@ constexpr auto multiplication_OverflowUnsafe( | |
); | ||
} | ||
|
||
template<int NB, typename T> | ||
constexpr auto expo_OverflowUnsafe( | ||
SWAR<NB, T> base, | ||
SWAR<NB, T> exponent | ||
) { | ||
return | ||
expo_OverflowUnsafe_SpecificBitCount<NB>( | ||
base, exponent | ||
); | ||
} | ||
|
||
template<int NB, typename T> | ||
struct SWAR_Pair{ | ||
SWAR<NB, T> even, odd; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,8 +41,24 @@ static_assert( | |
multiplication_OverflowUnsafe_SpecificBitCount<3>(Micand, Mplier).value() | ||
); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GOOD NEWS. Looks like my initial, first-pass implementation was correct after all! All value I tried when evaluating using the hex idiom you guys have already got provides consistently correct answers. |
||
TEST_CASE("Jamie's wip expo") { | ||
// the LSB lanes seem to be correct, but the MSB lanes are not... | ||
constexpr auto base = SWAR<8, u32>{0b0001'0011}; // 2 | 3 | ||
constexpr auto exponent = SWAR<8, u32>{0b0001'0010}; // 3 | 2 | ||
constexpr auto expected = SWAR<8, u32>{0b0001'1001}; // 8 | 9 | ||
// static_assert( | ||
// expected.value() == expo_OverflowUnsafe(base, exponent).value() | ||
// ); | ||
auto actual = expo_OverflowUnsafe(base, exponent); | ||
CHECK(expected.value() == actual.value()); | ||
auto expected_as_bits = std::bitset<32>(expected.value()); | ||
auto actual_as_bits = std::bitset<32>(actual.value()); | ||
printf("expected: %s\n", expected_as_bits.to_string().c_str()); | ||
printf("actual: %s\n", actual_as_bits.to_string().c_str()); | ||
} | ||
|
||
} // namespace Multiplication | ||
|
||
#define HE(nbits, t, v0, v1) \ | ||
static_assert(horizontalEquality<nbits, t>(\ | ||
SWAR<nbits, t>(v0),\ | ||
|
Uh oh!
There was an error while loading. Please reload this page.