1

Given an arbitrary floating point number, say -0.13, suppose we have an algorithm which calculates a binary string of known length L for this number, one by one, from left to right.

(I need to do this computation for calculating the Morton Key ordering for particles(co-orindates given) which in turn in used in building octrees. I am creating such binary strings for each of x,y,z dimensions)

Is it better/efficient to first create a character array of length L, and then convert this array into a string? i.e.

char ch[L]; for(i = 0; i < L; ++i) { // calculation of ch[i] } //convert array into string 

Or is it better/efficient to start of with a empty string, and then concatenate a new calculated bit into the string on the fly. i.e.

string s = ""; for(i = 0; i < L; ++i) { // calculation of ch[i] s = s + string(ch); } 
5
  • You could hack it and read out the bit pattern of the IEEE float binary representation :-) Commented Sep 6, 2011 at 22:53
  • 1
    Generally it's more efficient to place characters into an existing character array rather than concatenating a character to a string. But why are you worried about this? Unless you're doing it billions of times it's unlikely to make a difference. Use the code that's clearest. Commented Sep 6, 2011 at 22:55
  • Your second code sample is unclear; I've edited it. Is this what you meant to say? Commented Sep 6, 2011 at 22:56
  • yes i meant to say that. wrote the question in a rush. Sorry about that and thanks for the edit! Commented Sep 6, 2011 at 23:00
  • It should be noted that your first one does not create a valid, null-terminated char*. It is simply an array of chars. If you pass that to any function expecting a null-terminated char*, you will get unpleasant results. Commented Sep 6, 2011 at 23:25

6 Answers 6

5

Why not do both?

std::string myStr(L); for(i = 0; i < L; ++i) { // calculation of ch[i] myStr[i] = ch; } 

This creates a std::string with a given size. You then just set each character. This will only work if you can know the size beforehand exactly.

Alternatively, if you want something that is safe, even if you have to add more than L characters:

std::string myStr; myStr.reserve(L); for(i = 0; i < L; ++i) { // calculation of ch[i] myStr.push_back(ch); } 

std::string::reserve preallocates the storage, but push_back will allocate more if needs be. If you don't go past L characters, then you will only get the one initial allocation.

Sign up to request clarification or add additional context in comments.

3 Comments

push_back incurs a performance penalty; it has to check whether to grow the internal array.
@Oli: And it is also 100% impervious to buffer overruns. I'll take that tradeoff any day of the week.
The question was specifically about "efficiency", no matter how misguided that might be.
2

Can't you just use a string with a pre-allocated length?

string s(L, '\0'); for(i = 0; i < L; ++i) { // calculation of ch[i] } 

Comments

2

I'm not sure I fully understand the conversion happening, but we have objects for a reason. If you use std::string::reserve() first, the performance should be minuscule, and it's obvious what the intent is.

string s; s.reserve(L); for(i = 0; i < L; ++i) { // calculation of ch[i] string.push_back(ch); } 

If speed is absolutely necessary, you can instead initialize the string as length L, and bypass length checks:

string s(L,'\0'); for(i = 0; i < L; ++i) { // calculation of ch[i] string[i] = ch; } 

3 Comments

push_back incurs a performance penalty; it has to check whether to grow the internal array.
@Oli: I don't know how smart compilers are these days, but a data flow analysis after inlining should reveal that the test is redundant.
I left it there since it also incurs exceptions if you do it wrong, helping to prevent run-time errors. The faster method is not guaranteed to throw an exception.
2

Personally, i am probably out of date, but i use

sprintf ( char * str, const char * format, ... );

to create strings from numbers

sprintf ( outString,"%f", floatingPointNumber);

3 Comments

It's unclear if the OP is actually converting to base 10 or not. He just says "calculates a binary string of known length".
no i am not converting to base 10. I need the binary string only.
With the sprintf method, you end up with a binary string in an array, as the char * points to an array of chars.
2

Use the latter, but also call s.reserve(L) before entering the loop. This is almost as efficient as direct array assignment, but still easier to grok.

EDIT: Other answers suggest using push_back(). Vote for them.

Sidebar: I'm not sure what you are computing, but if you just want to generate a string representation of the number, I'd suggest you simply call sprintf(), or insert the number into a std::stringstream.

2 Comments

He he thanks for pointing that out! I wrote that question in a bit if a hurry! But someone has thankfully corrected my sin :-)
Doing this computation for calculating the Morton Keys used in building octrees. See edit
2

If you want the C++ way, use ostringstream. This is generally cleaner code, less error-prone, and easier to read:

float f = ... // whatever you set it to std::ostringstream s; s << f; std::string stringifiedfloat = s.str(); // now you have the float in a string. 

Alternately, you can use the C way, sprintf. This is generally more error-prone, and harder to read, but faster performance:

float f = ... // whatever you set it to char* buffer = new char[L]; sprintf(buffer, "%f", f); // now you have the float in a string. 

Or, you could even use boost's lexical_cast. This has better performance than ostringstream, and better readability than sprintf, but it gives you a dependency on boost:

float f = ... // whatever you set it to std::string stringified = boost::lexical_cast<std::string>(f); // now you have the float in a string. 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.