5
\$\begingroup\$
I have written a C++ program that calculates the floor of 64 divided by n for values of n from 1 to 64. I'm trying to get a faster SWAR algorithm that avoids costly divisions.
The problem is that the SWAR method uses a lot of magic numbers.
I used constexpr functions to show the origin of the magic numbers, but the code has become long and unreadable.
Is it possible to find a middle ground where the code is both concise and readable? Or should I leave the long constexpr code?
Here is my code:
#include
#include
#include
#include
// Function floor(64/n)=â64/nâ, for 0(64u / n);
}
// Function to generate an array of â64/nâ values for n from 1 to 64
constexpr std::array generateResultArray()
{
std::array result = {};
for (uint8_t i = 1; i RESULT_TO_GENERATE = generateResultArray();
// Union to allow access to a 64-bit integer as an array of 8-bit integers
union Union64_8
{
uint64_t as_uint64;
std::array as_array_uint8;
};
// Function to generate an array of indices n, where the value of â64/nâ changes
constexpr Union64_8 jumpsBy1()
{
Union64_8 jumps = {0};
jumps.as_array_uint8 = {};
uint8_t idx = 0;
for (uint8_t i = 8; i RESULT_TO_GENERATE[i + 1])
{
jumps.as_array_uint8[idx++] = i;
}
}
jumps.as_array_uint8[idx] = 65u;
return jumps;
}
// Precomputed array of indices where the value of â64/nâ changes
constexpr Union64_8 JUMPS_BY_1 = jumpsBy1();
// Multiplicator array initialized to all ones.
// By multiplying with an 8 bit uint, makes 8 copies bitshifted.
constexpr Union64_8 MULTIPLICATOR = {.as_array_uint8 = {{1, 1, 1, 1, 1, 1, 1, 1}}};
// This array of compare flags is initialized with each element set to 0b10000000 (128 in decimal)
// It is used to flag the bits that change during multiple SWAR comparison operations x> (8 * n)) & 255ULL;
}
// For n >= 8, use the SWAR technique
uint64_t substraction = (JUMPS_BY_1.as_uint64 | COMPARE_FLAGS.as_uint64) - n * MULTIPLICATOR.as_uint64;
uint8_t result = __builtin_popcountll(substraction & COMPARE_FLAGS.as_uint64);
return result;
};
int main()
{
// Print the precomputed array of â64/nâ values
std::cout (RESULT_TO_GENERATE[i]) (jump) (n) (result) << std::endl;
}
return 0;
}
c++performanceconstantsc++23constant-expression
Share
Follow
edited 6 hours ago
J_H
35.5k33 gold badges3333 silver badges130130 bronze badges
asked 9 hours ago
wepajakegwepajakeg
16377 bronze badges
\$\endgroup\$
1
2
\$\begingroup\$
Using a union for type punning is not legal in C++.
\$\endgroup\$
– indi
Commented
9 hours ago
Add a comment
|