constexpr log10 Function for Integers
Asked Answered
W

2

11

So I need log10 functionality to find the number of characters required to store a given integer. But I'd like to get it at compile time to determine the length of char arrays statically based on these integer constants defined in my code. Unfortunately log10 is not a constexpr function, even the integer version. I could make an integral version like this:

template <typename T>
constexpr enable_if_t<is_integral_v<T>, size_t> intlen(T param) {
    size_t result{ 1U };

     while(T{} != (param /= T{ 10 })) ++result;
     return result;
}

Which will finally allow me to do: const char foo[intlen(13) + 1U]
Does already give me a tool for this or do I have to define my own?

Whimsey answered 1/10, 2018 at 12:40 Comment(16)
What is your question exactly?Extrauterine
@DanM. "Does c++ already give me a tool for this or do I have to define my own?"Nonchalant
What's wrong with const char foo [] = "13"? That will initialise foo as an array of three char, without the need to type 13 twice.Cordoba
@MartinBonner That's a very vague question. What is "this"? It looks like Johnathan has already found out that log10 is not constexpr and also has come up with a solution. What other tools he is asking for?Extrauterine
@Peter: A better example might be: char buffer[intlen(UINT_MAX)+1u]; which creates a buffer big enough to hold any unsigned int.Nonchalant
@MartinBonner - that can be done with char buffer[std::numeric_limits<unsigned>::digits10 + 1]. BTW: what downvotes are you referring to in your previous comment? - as far as I can see this question has only been upvoted twice.Cordoba
@Cordoba This is a toy example. I'm going to be concatenating the length of a defined number with other lengthsWhimsey
@Peter: OK, that's fine for the specific example of UINT_MAX (and similar variables), but if you have some other limit, then being able to create an appropriately sized buffer is useful. (Downvotes - they've gone away. It was at -2).Nonchalant
@DanM. I'm asking how I can calculate the exact number of character needed to contain a given string. This is obviously a toy example, I'll be concatenating multiple integer lengths and only assigning the contents of foo at runtime.Whimsey
@Jonathan Mee if you know the string already, when it'd be just strlen(your string) + 1, nothing to do with integers. Same when assigning literals, compiler can deduce the length automatically. If you want to calculate integral log10 and compile-time, when you'll have to use your function. What's wrong with it and why do you think it's not a "tool" c++ gives you?Extrauterine
@DanM. I've tried to clarify the question some... But let's say that I have done #define FOO 13 and #define BAR 42 now I want a char[] that will exactly contain these numbers along with the value in constexpr size_t formatting. I want to be able to do something like: const char foo[intlen(13) + formatting + intlen(42) + 1U] does that less toy example make sense? My hope was that there was already something available to me in the standard and I didn't have to author intlenWhimsey
@JonathanMee: size it for the maximum integer length and be happy with it. For ridicule allocations like these the stack is essentially free, it makes zero sense trying to optimize them, unless you are on extremely constrained platforms. BTW if they are defines you can also use the preprocessor stringizing operator, but I don't think it's worth it.Monomer
@JonathanMee is the string you are trying to assign also compile time? If so, you might be better of just calculating it's size instead (if it only contains string representations of compile-time constants it usually can be). And if it's something simple like char a[] = "abc" "123" "0.15";, the compiler will deduce its size automatically.Extrauterine
@DanM. Nope the string will be populated at runtime, so I cannot just directly assign the string :(Whimsey
@MatteoItalia You probably have a reasonable point... and I'm not extremely limited. However if it was simple I didn't see any harm in clamping the size correctly. But... it does appear there isn't a simple solution here.Whimsey
@JonathanMee there might be, depending on what exactly you want to do. You can forget about compile-time for a moment and think about how to calculate some required buffer size at all (even at runtime), and then translate it to constexpr. If your string has compile-time computable size, then you can implement it. C++14 constexpr facilities are rather powerful.Extrauterine
M
2

std::log10 has to be no constexpr by standard.

As there as no constexpr alternative, you have to write your own version (or use library which provides one).

Mammalian answered 1/10, 2018 at 12:54 Comment(0)
E
6

If you only want to get max digits (base10) for given integral (and floating point) type (not specific value, i.e. enough for all values), you can use: std::numeric_limits::max_digits10 and std::numeric_limits::digits10

The value of std::numeric_limits::max_digits10 is the number of base-10 digits that are necessary to uniquely represent all distinct values of the type T

The value of std::numeric_limits::digits10 is the number of base-10 digits that can be represented by the type T without change, that is, any number with this many significant decimal digits can be converted to a value of type T and back to decimal form, without change due to rounding or overflow.

However, if you want to find constexpr "length" of a specific constant, you'll have to use your custom function.

Extrauterine answered 1/10, 2018 at 12:52 Comment(1)
Note that max_digits10 is only meaningful for floating point types, not for integer types.Leakey
M
2

std::log10 has to be no constexpr by standard.

As there as no constexpr alternative, you have to write your own version (or use library which provides one).

Mammalian answered 1/10, 2018 at 12:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.