Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C array comparison

Is the defacto method for comparing arrays (in C) to use memcmp from string.h?

I want to compare arrays of ints and doubles in my unit tests

I am unsure whether to use something like:

double a[] = {1.0, 2.0, 3.0};
double b[] = {1.0, 2.0, 3.0};
size_t n = 3;
if (! memcmp(a, b, n * sizeof(double)))
    /* arrays equal */

or to write a bespoke is_array_equal(a, b, n) type function?

like image 416
bph Avatar asked Dec 06 '11 12:12

bph


People also ask

Can I compare arrays in C?

compareArray() will compare elements of both of the array elements and returns 0 if all elements are equal otherwise function will return 1.

Can you use == to compare arrays?

While comparing two arrays we can not use “==” operator as it will compare the addresses of the memory block to which both the arrays are pointing.

How do I compare two arrays of arrays?

Using Arrays. equals(array1, array2) methods − This method iterates over each value of an array and compare using equals method. Using Arrays. deepEquals(array1, array2) methods − This method iterates over each value of an array and deep compare using any overridden equals method.


2 Answers

memcmp would do an exact comparison, which is seldom a good idea for floats, and would not follow the rule that NaN != NaN. For sorting, that's fine, but for other purposes, you might to do an approximate comparison such as:

bool dbl_array_eq(double const *x, double const *y, size_t n, double eps)
{
    for (size_t i=0; i<n; i++)
        if (fabs(x[i] - y[i]) > eps)
            return false;
    return true;
}
like image 70
Fred Foo Avatar answered Sep 22 '22 17:09

Fred Foo


Using memcmp is not generally a good idea. Let's start with the more complex and work down from there.


Though you mentioned int and double, I first want to concentrate on memcmp as a general solution, such as to compare arrays of type:

struct {
    char c;
    // 1
    int i;
    // 2
}

The main problem there is that implementations are free to add padding to structures at locations 1 and 2, making a bytewise comparison potentially false even though the important bits match perfectly.


Now down to doubles. You might think this was better as there's no padding there. However there are other problems.

The first is the treatment of NaN values. IEEE754 goes out of its way to ensure that NaN is not equal to any other value, including itself. For example, the code:

#include <stdio.h>
#include <string.h>

int main (void) {
    double d1 = 0.0 / 0.0, d2 = d1;

    if (d1 == d2)
        puts ("Okay");
    else
        puts ("Bad");

    if (memcmp (&d1, &d2, sizeof(double)) == 0)
        puts ("Okay");
    else puts
        ("Bad");

    return 0;
}

will output

Bad
Okay

illustrating the difference.

The second is the treatment of plus and minus zero. These should be considered equal for the purposes of comparison but, as the bit patterns are different, memcmp will say they are different.

Changing the declaration/initialisation of d1 and d2 in the above code to:

 double d1 = 0.0, d2 = -d1;

will make this clear.


So, if structures and doubles are problematic, surely integers are okay. After all, they're always two's complement, yes?

No, actually they're not. ISO mandates one of three encoding schemes for signed integers and the other two (ones' complements and sign/magnitude) suffer from a similar problem as doubles, that fact that both plus and minus zero exist.

So, while they should possibly be considered equal, again the bit patterns are different.

Even for unsigned integers, you have a problem (it's also a problem for signed values as well). ISO states that these representations can have value bits and padding bits, and that the values of the padding bits are unspecified.

So, even for what may seem the simplest case, memcmp can be a bad idea.

like image 28
paxdiablo Avatar answered Sep 22 '22 17:09

paxdiablo