HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Fill a vector with uniformly distributed random complex numbers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
randomuniformlywithnumbersdistributedvectorfillcomplex

Problem

I want to fill an array of complex numbers using a uniform generator. I thought up the next code. (Complex is a simple fixed-point complex data type.)

std::generate(inputData.begin(), inputData.end(), []()-> Complex {
    static std::default_random_engine generator;
    static std::normal_distribution distribution(0.0, 0.5); // mean = 0.0, stddev = 0.5
    return Complex(distribution(generator), distribution(generator));
});


So I though up using static variables within the lambda expression. Is that inefficient? Alternatively I would create them outside of the lambda, and put them on the capture list. But I don't need them outside of the lambda, so this seems cleaner to me.

Solution

The problem with this is that it leaks memory, although not in the traditional sense of leaking.

Function static variables live till the end of the program. So while generator and distribution are only created when this code is first run, they only get destroyed at the end of your program even though you never use them later. This eats up memory the entire time.

On the other hand, the amount of memory it eats up is pretty small and constant, so for almost all purposes, it shouldn't make too big of a difference. Even if you repeatedly called a function that had this code in it, the static variable would live and not be recreated. Just don't use this in a way that generates the lambda 100s of times, such as in intense template metaprogramming.

In C++17, if you were using this to initialize a big enough vector, you could make use of execution policies to parallelize this like so:

std::generate(std::execution::par_unseq, inputData.begin(), inputData.end(), []()-> Complex {
    thread_local std::default_random_engine generator; // thread_local so we don't have to do any locking
    thread_local std::normal_distribution distribution(0.0, 0.5); // mean = 0.0, stddev = 0.5
    return Complex(distribution(generator), distribution(generator));
});


This has the added benefit that these variables will be destructed when the threads used finish, although when that happens is mostly unclear.

Code Snippets

std::generate(std::execution::par_unseq, inputData.begin(), inputData.end(), []()-> Complex {
    thread_local std::default_random_engine generator; // thread_local so we don't have to do any locking
    thread_local std::normal_distribution<double> distribution(0.0, 0.5); // mean = 0.0, stddev = 0.5
    return Complex(distribution(generator), distribution(generator));
});

Context

StackExchange Code Review Q#155513, answer score: 3

Revisions (0)

No revisions yet.