February 01, 2007
I'm having a problem with an if statement not catching some floating-point zeros. I know that there are 9 values in the array, but only 7 are found by the if and outputted by the debug statement. If I remove the if statement and the code in its block, all 9 of the zeros are printed by the debug statement.

Does anyone have any idea what might be the problem?

Thanks,
JonathanC

Code:
------------------------------------------------------------------------------------------
    uint zeros = 0;
    real test = .01;
    uint size = X.Rows;
    for (uint i = 0; i < size; i++)
    {
        real r = X.Data[i];
        debug (calcXHI) writefln("i:", i, ", r:", r);
        if (std.math.abs(r) <= test)
        {
            zeros++;
            size--;
            for (j = i + 1; j < size; j++)
            {
                X.Data[j - 1] = X.Data[j];
            }
        }
    }
February 01, 2007
JonathanC wrote:
> I'm having a problem with an if statement not catching some floating-point zeros. I know that there are 9 values in the array, but only 7 are found by the if and outputted by the debug statement. If I remove the if statement and the code in its block, all 9 of the zeros are printed by the debug statement.
> 
> Does anyone have any idea what might be the problem?
> 
> Thanks,
> JonathanC
> 
> Code:
> ------------------------------------------------------------------------------------------
>     uint zeros = 0;
>     real test = .01;
>     uint size = X.Rows;
>     for (uint i = 0; i < size; i++)
>     {
>         real r = X.Data[i];
>         debug (calcXHI) writefln("i:", i, ", r:", r);
>         if (std.math.abs(r) <= test)
>         {
>             zeros++;
>             size--;
>             for (j = i + 1; j < size; j++)
>             {
>                 X.Data[j - 1] = X.Data[j];
>             }
>         }
>     }

So you're removing the zeros by copying the part of the array after every zero one place forward?

First of all, you should probably decrease 'size' after the inner loop to preserve the last element.

It looks like you forgot to also decrease i when you do that, so if there are two consecutive zeros you miss the second one.

So that gets you this (modified to make X a regular array):
---
import std.stdio;
import std.math;

void main() {
    float[] X = [ 0f, 1, 2, 0, 0, 3, 4, 5, 0, 6, 7, 0, 0, 8];
    writefln(X);

    uint zeros = 0;
    real test = .01;
    uint size = X.length;
    for (uint i = 0; i < size; i++)
    {
        real r = X[i];
        debug (calcXHI) writefln("i:", i, ", r:", r);
        if (std.math.abs(r) <= test)
        {
            zeros++;
            for (size_t j = i + 1; j < size; j++)
            {
                X[j - 1] = X[j];
            }
            size--;
        i--;
        }
    }

    writefln(X[0 .. size]);
}
---

Also, this code might be more efficient: (will only copy values once at most)
---
import std.stdio;
import std.math;

void main() {
    float[] X = [ 0f, 1, 2, 0, 0, 3, 4, 5, 0, 6, 7, 0, 0, 8];
    writefln(X);

    uint zeros = 0;
    real test = .01;
    uint size = X.length;
    // k is the next element to inspect.
    // i is the next location to copy to.
    // loop ends when k >= X.length (not size) because later elements
    // aren't moved anymore.
    for (uint i = 0, k = 0; k < X.length; k++)
    {
        real r = X[k];
        debug (calcXHI) writefln("i:", i, ", k:", k, ", r:", r);
        if (std.math.abs(r) <= test)
        {
            zeros++;
            size--;
        }
        else
        {
            // copy next element (can be conditional on (zeros > 0) or,
            // if you prefer,  (i != k)
            X[i] = r;
            i++;
        }
    }

    writefln(X[0 .. size]);
}
---