Dynamically allocating and setting to zero an array of floats
Asked Answered
H

7

19

How do I automatically set a dynamically allocated array of floats to zero(0.0) during allocation

Is this OK

float* delay_line = new float[filter_len];

//THIS
memset(delay_line, 0.0, filter_len); //can I do this for a float??

//OR THIS
for (int i = 0; i < filter_len; i++)
  delay_line[i] = 0.0;

Which is the most efficient way

Thanks

Hauser answered 18/5, 2009 at 12:2 Comment(0)
E
34

Use sizeof(float) * filter_len unless you are working in some odd implementation where sizeof(float) == sizeof(char).

memset(delay_line, 0, sizeof(float) * filter_len);

Edit: As Stephan202 points out in the comments, 0.0 is a particularly easy floating point value to code for memset since the IEEE standard representation for 0.0 is all zero bits.

memset is operating in the realm of memory, not the realm of numbers. The second parameter, declared an int, is cast to an unsigned char. If your implementation of C++ uses four bytes per float, the following relationships hold:

  • If you memset the float with 0, the value will be 0.0.
  • If you memset the float with 1, the value will be 2.36943e-38.
  • If you memset the float with 42, the value will be 1.51137e-13.
  • If you memset the float with 64, the value will be 3.00392.

So zero is a special case.

If this seems peculiar, recall that memset is declared in <cstring> or <string.h>, and is often used for making things like "***************" or "------------------". That it can also be used to zero memory is a nifty side-effect.

As Milan Babuškov points out in the comments, there is a function bzero (nonstandard and deprecated), available for the moment on Mac and Linux but not Microsoft, which, because it is specially tailored to setting memory to zero, safely omits a few instructions. If you use it, and a puritanical future release of your compiler omits it, it is trivial to implement bzero yourself in a local compatibility patch, unless the future release has re-used the name for some other purpose.

Ethics answered 18/5, 2009 at 12:6 Comment(5)
Thanks, will this set each value in delay_line to 0.0?Hauser
Yes, this will set each value to 0.0: if sign, exponent and fraction are 0, then the float represents 0.0: en.wikipedia.org/wiki/IEEE_754-1985Humankind
IEEE 754 is completely unrelated to C++ standard. There is nothing in C++ standard that says implementations must follow IEEE 754.Ruler
Also, if you go down this path, bzero should be faster than memset: fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdownRuler
@Milan: Agreed, bzero is more expressive of programmer intent. Looking at the implementations of bzero.c and memset.c in glibc, bzero is able to dispense with a few |= operations because it does not need to deal with the case of someone passing 268435521 because he wants 'A'. bzero isn't standard C, alas.Ethics
E
15

use

#include <algorithm>
...
std::fill_n( delay_line, filer_len, 0 )
Elwaine answered 18/5, 2009 at 12:5 Comment(2)
If not you cannot use a vector, this is the most type-safe, modern c++ way to do it. memset might be faster, but it just zeros bytes with no type-checking, if you get your math wrong you are in trouble.Salsbury
I agree on fill_n being the preferred method, even if it's slightly slower (and I'll only believe that when I see it ;) As opposed to memset, this method is both type safe and much easier 'extensible/adaptable' (you can use this method to initialize to e.g. 4.2 too)Achondrite
N
15

The elements of a dynamically allocated array can be initialized to the default value of the element type by following the array size by an empty pair of parentheses:

float* delay_line = new float[filter_len]();
Nomism answered 18/5, 2009 at 22:37 Comment(1)
Modern-C++ wise: shouldn't this be promoted to the best answer?Ultramundane
V
11

Use a std::vector instead:

std::vector<float> delay_line( filter_len );

The vector will be zero initialised.

Vizierate answered 18/5, 2009 at 12:8 Comment(5)
Not the most efficient way, but surely the most elegant.Repair
It's the most efficient in terms of programmer effort (no need to manage destruction) and that is normally the most important thing to optimise.Vizierate
There is no need to manage destruction or construction for an array on the stack :-)Ethics
The most efficient way in terms of programmer effort is to get the manager to mark the request which requires the zeroed float array "WONT FIX".Ethics
Thomas, you should put that in your resume: "experience with avoiding to fix things"Repair
E
3

Now that we're at it: even better would be to use the vector class.

std::vector< float > delay_line( filter_len, 0.0 );
Elwaine answered 18/5, 2009 at 12:8 Comment(1)
But take a look at Neil's answer: you won't need the 0.0 argument: this is the default initialization argument value.Elwaine
B
3

Another option is to use calloc to allocate and zero at the same time:

float *delay_line = (float *)calloc(sizeof(float), filter_len);

The advantage here is that, depending on your malloc implementation, it may be possible to avoid zeroing the array if it's known to be allocated from memory that's already zeroed (as pages allocated from the operating system often are)

Keep in mind that you must use free() rather than delete [] on such an array.

Briquet answered 18/5, 2009 at 22:57 Comment(0)
B
2

Which is the most efficient way

memset maybe a tad faster, BUT WHO CARES!?!? Micro-optimization down to this level is a total waste of time, unless you're programming a calculator, and probably not even then.

I think the memset way is clearer, BUT I think you really had better check your man-pages for memset... I'd be suprised if your version of standard libraries has a memset function which takes a float as the second argument.

PS: The bit pattern representing zero is the same for both integers and floats... this is by design, not just good luck.

Good Luck ;-)

Cheers. Keith.

Berg answered 18/5, 2009 at 12:15 Comment(2)
Bashing micro-optimization is a total waste of time. If the QS didn't need optimization, why would he ask which is the most efficient way?Repair
I prefer memset but was unsure if binary representation of a floating point zero is the same as integer zero Thanks for clearing that upHauser

© 2022 - 2024 — McMap. All rights reserved.