mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-11 13:10:45 +00:00
Add general math function to get number of base 10 digits required
This commit is contained in:
parent
282f13cab0
commit
4ce8a36e4d
@ -147,3 +147,23 @@ uint32_t RXDecompressUint(uint16_t num)
|
||||
if (num > 0x100) return ((num - 0x100) << 3) + 0x100;
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Algorithm from https://lemire.me/blog/2021/05/28/computing-the-number-of-digits-of-an-integer-quickly/ */
|
||||
uint GetBase10DigitsRequired32(uint32_t x)
|
||||
{
|
||||
static uint32_t table[] = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999};
|
||||
int log2 = std::countl_zero<uint32_t>(1) - std::countl_zero<uint32_t>(x | 1);
|
||||
int log10approx = (9 * log2) >> 5;
|
||||
if (x > table[log10approx]) log10approx++;
|
||||
return log10approx + 1;
|
||||
}
|
||||
|
||||
uint GetBase10DigitsRequired64(uint64_t x)
|
||||
{
|
||||
/* Rather than using a huge lookup table for 64 bit values, use a loop */
|
||||
uint64_t threshold = 10;
|
||||
for (uint i = 1; i < 20; i++, threshold *= 10) {
|
||||
if (x < threshold) return i;
|
||||
}
|
||||
return 20; // Largest number of digits required for uint64_t
|
||||
}
|
||||
|
@ -433,6 +433,21 @@ constexpr inline T SaturatingAdd(T a, T b)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of base 10 digits required for an unsigned value.
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_unsigned_v<T>, int> = 0>
|
||||
constexpr inline uint GetBase10DigitsRequired(T x)
|
||||
{
|
||||
if (sizeof(T) <= sizeof(uint32_t) || x <= UINT32_MAX) {
|
||||
extern uint GetBase10DigitsRequired32(uint32_t x);
|
||||
return GetBase10DigitsRequired32(static_cast<uint32_t>(x));
|
||||
} else {
|
||||
extern uint GetBase10DigitsRequired64(uint64_t x);
|
||||
return GetBase10DigitsRequired64(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t IntSqrt(uint32_t num);
|
||||
uint32_t IntSqrt64(uint64_t num);
|
||||
|
@ -110,11 +110,7 @@ StringParameter *StringParameters::GetNextParameterPointer()
|
||||
*/
|
||||
void SetDParamMaxValue(size_t n, uint64_t max_value, uint min_count, FontSize size)
|
||||
{
|
||||
uint num_digits = 1;
|
||||
while (max_value >= 10) {
|
||||
num_digits++;
|
||||
max_value /= 10;
|
||||
}
|
||||
uint num_digits = GetBase10DigitsRequired(max_value);
|
||||
SetDParamMaxDigits(n, std::max(min_count, num_digits), size);
|
||||
}
|
||||
|
||||
|
@ -105,3 +105,37 @@ TEST_CASE("SaturatingAdd")
|
||||
CHECK(SaturatingAdd<uint8_t>(255, 1) == 255);
|
||||
CHECK(SaturatingAdd<uint8_t>(0, 254) == 254);
|
||||
}
|
||||
|
||||
TEST_CASE("GetBase10DigitsRequired")
|
||||
{
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(0) == 1);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(1) == 1);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(9) == 1);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(10) == 2);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(99) == 2);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(100) == 3);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(999) == 3);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(1000) == 4);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(9999) == 4);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(10000) == 5);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(99999) == 5);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(100000) == 6);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(999999) == 6);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(1000000) == 7);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(9999999) == 7);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(10000000) == 8);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(99999999) == 8);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(100000000) == 9);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(999999999) == 9);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(1000000000) == 10);
|
||||
CHECK(GetBase10DigitsRequired<uint32_t>(UINT32_MAX) == 10);
|
||||
CHECK(GetBase10DigitsRequired<uint64_t>(9999999999ULL) == 10);
|
||||
CHECK(GetBase10DigitsRequired<uint64_t>(10000000000ULL) == 11);
|
||||
CHECK(GetBase10DigitsRequired<uint64_t>(99999999999ULL) == 11);
|
||||
CHECK(GetBase10DigitsRequired<uint64_t>(100000000000ULL) == 12);
|
||||
CHECK(GetBase10DigitsRequired<uint64_t>(999999999999ULL) == 12);
|
||||
CHECK(GetBase10DigitsRequired<uint64_t>(1000000000000000000ULL) == 19);
|
||||
CHECK(GetBase10DigitsRequired<uint64_t>(9999999999999999999ULL) == 19);
|
||||
CHECK(GetBase10DigitsRequired<uint64_t>(10000000000000000000ULL) == 20);
|
||||
CHECK(GetBase10DigitsRequired<uint64_t>(UINT64_MAX) == 20);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user