dtarb / TauDEM

Terrain Analysis Using Digital Elevation Models (TauDEM) software for hydrologic terrain analysis and channel network extraction.
http://hydrology.usu.edu/taudem
Other
222 stars 115 forks source link

linearpart.h: Handle NaN NoData properly #264

Open HuidaeCho opened 2 months ago

HuidaeCho commented 2 months ago

This PR fixes handling of NoData that is NaN. Subtracting a NaN value from a non-NaN or NaN value yields NaN and comparing this result with MINEPS will always return false because comparisons on NaN do not produce a signal (Not-a-Number).

Testing code:

#include <math.h>
#include <cstdio>

#define MINEPS 1e-30

int main()
{
    bool isNoData;
    double noData = NAN;

    // this cell is NoData
    double noDataCell = NAN;
    // this cell is not NoData
    double dataCell = 123;

    //---------------------------------------------------------
    printf("## Before this PR\n");
    printf("* no data cell:\t");
    isNoData = abs(noDataCell - noData) < MINEPS;
    if (isNoData)
        // expected output
        printf("NoData\n");
    else
        // actual output
        printf("Not NoData (incorrect)\n");

    printf("* data cell:\t");
    isNoData = abs(dataCell - noData) < MINEPS;
    if (isNoData)
        printf("NoData\n");
    else
        // expected and actual output
        printf("Not NoData (correct)\n");
    printf("\n");

    //---------------------------------------------------------
    printf("## After this PR\n");
    printf("* no data cell:\t");
    isNoData = (isnan(noData) && isnan(noDataCell)) ||
               (!isnan(noData) && abs(noDataCell - noData) < MINEPS);
    if (isNoData)
        // expected and actual output
        printf("NoData (correct)\n");
    else
        printf("Not NoData\n");

    printf("* data cell:\t");
    isNoData = (isnan(noData) && isnan(dataCell)) ||
               (!isnan(noData) && abs(dataCell - noData) < MINEPS);
    if (isNoData)
        printf("NoData\n");
    else
        // expected and actual output
        printf("Not NoData (correct)\n");
}

Result:

$ c++ -o test test.cpp -Wall; ./test
## Before this PR
* no data cell: Not NoData (incorrect)
* data cell:    Not NoData (correct)

## After this PR
* no data cell: NoData (correct)
* data cell:    Not NoData (correct)