Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic function for comparing two integers?

Tags:

c

Is there a fairly standard C (Linux) function, or a code-efficient but good-performing approach, for comparing two integers of an arbitrary size?

I'm looking for something with the parameters int intcmp(const void *a, const void *b, size_t size) that works on integers a and b for any practical size size. (memcmp() would work (I think) if the architecture was big endian.)

The implementation I tend to use goes like this (with improvements from Efficient integer compare function) but it's not completely generic and has enough of a code overhead that I generally think twice before slotting it in.

int intcmp(const void *a, const void *b, size_t size) {

    #define CASE_SIZE_RETURN_A_B_CMP(_t) \
        case sizeof(_t): \
            return ((*(_t *)(a) > *(_t *)(b)) - (*(_t *)(a) < *(_t *)(b)))

    switch (size) {
    CASE_SIZE_RETURN_A_B_CMP(char);
    CASE_SIZE_RETURN_A_B_CMP(short);
    CASE_SIZE_RETURN_A_B_CMP(int);
    CASE_SIZE_RETURN_A_B_CMP(long long);
    }
    #undef CASE_SIZE_RETURN_A_B_CMP

    assert(0);
    return 0;
}
like image 801
antak Avatar asked May 13 '13 05:05

antak


People also ask

What are generic functions in Swift?

Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.

How do you add two generic numbers?

You have to add the numbers as the same type, so you could do x. intValue() + y.

How do you compare numbers in Java?

Java Integer compare() methodpublic static int compare(int x, int y) Parameter : x : the first int to compare y : the second int to compare Return : This method returns the value zero if (x==y), if (x < y) then it returns a value less than zero and if (x > y) then it returns a value greater than zero.


2 Answers

Static inline functions have the advantage of the arguments being evaluated only once (this is hard/impossible to do with macros) . This would allow function calls like int diff = cmp_all (p++, q++, sizeof *p); :

#include <stdlib.h>
#include <stdint.h>

static inline int cmp1(const int8_t *one, const int8_t *two)
{
if (*one < *two) return -1;
else if (*one > *two) return 1;
else return 0;
}

static inline int cmp2(const int16_t *one, const int16_t *two)
{
if (*one < *two) return -1;
else if (*one > *two) return 1;
else return 0;
}

static inline int cmp4(const int32_t *one, const int32_t *two)
{
if (*one < *two) return -1;
else if (*one > *two) return 1;
else return 0;
}

static inline int cmp8(const int64_t *one, const int64_t *two)
{
if (*one < *two) return -1;
else if (*one > *two) return 1;
else return 0;
}

int cmp_all(const void *one, const void *two, size_t size)
{
switch(size) {
case 1: return cmp1(one, two);
case 2: return cmp2(one, two);
case 4: return cmp4(one, two);
case 8: return cmp8(one, two);
default: return 0; /* that will teach them ... */
        }
}
like image 183
wildplasser Avatar answered Nov 15 '22 21:11

wildplasser


If you really need to good performing comparation of integers of arbitrary sizes I recommend you look at The GNU Multiple Precision Arithmetic Library. That requires you to use it's special mpz_t type (which has the length included). Then you can use the function int mpz_cmp(mpz_t op1, mpz_t op2). Deciding on your own representation of big integers and implement it in way that is both fairly portable and efficient is not trivial.

If, on the other hand, you just need the standard integer sizes you mention I think your implementation is fine. But for even better portability you shouldn't make assumptions on the various integer sizes:

#include <stdint.h>

int intcmp(const void *a, const void *b, size_t size) {
    switch (size) {
    case 1: return (*(int8_t*)a > *(int8_t*)b) - (*(int8_t*)a < *(int8_t*)b)
    case 2: return (*(int16_t*)a > *(int16_t*)b) - (*(int16_t*)a < *(int16_t*)b)
    case 4: return (*(int32_t*)a > *(int32_t*)b) - (*(int32_t*)a < *(int32_t*)b)
    case 8: return (*(int64_t*)a > *(int64_t*)b) - (*(int64_t*)a < *(int64_t*)b)
    }

    assert(0);
    return 0;
}

Perhaps you'll find it better to create a separate function for each length you need instead of using the same for all? And finally, if efficiency is important, it is often less efficient to do arithmetics with char or short than with int. So try to avoid the cases where you need to call this function with char or short and use int instead.

like image 28
Fabel Avatar answered Nov 15 '22 21:11

Fabel