skwear - 1 year ago 78
C# Question

# Is there a faster way to loop over an array in safe mode

I am writing a method to measure the frequency of a sampled sine wave. It takes a somewhat large 1D array (10^3 to 10^4 samples order of magnitude) and returns a

`double`
. A helper methods is also called within the body of the method that checks whether the wave is crossing zero. Here is an example of what I have written:

``````public static double Hertz(float[] v, int n) {
int nZCros = 0
for (int i = 1; i < n; i++) {
if (IsZeroCrossing(v.Skip(i - 1).ToArray())) {
++nZCros;
}
}
return (double)nZCros / 2.0;
}
private static bool IsZeroCrossing(float[] v) {
bool cross;
//checks if the first two elements of the array are opposite sign or not
return cross;
}
``````

My problem is that method takes 200-300 ms to run. So I decided to try using
`unsafe`
and pointers, like this,

``````public unsafe static double Hertz(float* v, int n) {
int nZCros = 0
for (int i = 1; i < n; i++) {
if (IsZeroCrossing(&v[i - 1])) {
++nZCros;
}
}
return (double)nZCros / 2.0;
}
private unsafe static bool IsZeroCrossing(float* v) {
bool cross;
//checks if the first two elements of the array are opposite sign or not
return cross;
}
``````

which runs in 2-4 ms.

However, I am not really comfortable with venturing outside the recommended bounds. Is there a way to achieve the same speed in a safe context? And if there isn't, does it defeat the purpose of using C#? Should I really be using C# for these kind of signal processing applications and scientific implementations?

This is just one of many DSP methods I'm writing which take a large array of samples as an input. But this one got me to realize there was a problem, because I accidentally put in 48000 samples instead of 4800 when I was testing this method and it took 20 seconds to return a value.

Thank you.

`Take(2)`
after
`Skip(i - 1)`
in the former snippet. This brought it down to 90-100 ms, but the question still stands.

You don't need to pass a copy of the array elements to `IsZeroCrossing()`.

Instead, just pass the two elements you are interested in:

``````private static bool IsZeroCrossing(float elem1, float elem2)
{
return elem1*elem2 < 0.0f; // Quick way to check if signs differ.
}
``````

And call it like so:

``````if (IsZeroCrossing(v[i-1], v[i]) {
``````

It's possible that such a simple method will be inlined for a release build, making it as fast as possible.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download