Общая функция для сравнения двух целых чисел?

Существует ли стандартная функция C (Linux) или эффективный с точки зрения кода, но эффективный подход для сравнения двух целых чисел произвольного размера?

Я ищу что-то с параметрами int intcmp(const void *a, const void *b, size_t size), которые работают с целыми числами a и b для любого практического размера size. (memcmp() будет работать (я думаю), если архитектура была большой endian.)

Реализация, которую я обычно использую, выглядит следующим образом (с улучшением Эффективная функция сравнения целого числа), но она не является полностью общей и имеет достаточное количество служебных данных кода, которые я обычно дважды подумайте, прежде чем вставлять его.

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;
}

Ответы

Ответ 1

Статические встроенные функции имеют преимущество аргументов, которые оцениваются только один раз (это трудно или невозможно сделать с макросами). Это позволило бы вызвать вызовы функций, такие как 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 ... */
        }
}

Ответ 2

Если вам действительно нужно хорошо провести сравнение целых чисел произвольных размеров, я рекомендую вам посмотреть Библиотека многоточечной арифметики GNU. Это требует от вас использования специального типа mpz_t (который включает длину). Затем вы можете использовать функцию int mpz_cmp(mpz_t op1, mpz_t op2). Решение о вашем собственном представлении больших целых чисел и его реализация таким образом, который является достаточно портативным и эффективным, не является тривиальным.

Если, с другой стороны, вам просто нужны стандартные значения целого числа, о которых вы говорите, я думаю, что ваша реализация в порядке. Но для еще лучшей переносимости вы не должны делать предположений о различных размерах целого числа:

#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;
}

Возможно, вам будет лучше создать отдельную функцию для каждой необходимой длины, а не использовать ее для всех? И, наконец, если эффективность важна, часто бывает менее эффективно делать арифметику с char или короткой, чем с int. Поэтому старайтесь избегать случаев, когда вам нужно вызвать эту функцию с помощью char или short и вместо этого использовать int.

Ответ 3

Я думаю, что следующая ссылка поможет. Вы проводите сравнение, не используя компараторы, которые немного сокращают ваш код. Я использовал код, связанный с этой ссылкой, в прошлом.

- Хорошая охота -

Программа C для сравнения целых чисел без использования логических операторов?

Ответ 4

Если сайт вызова имеет доступный размер, я бы предпочел использовать его в качестве индекса в справочной таблице, чтобы сразу вызвать надлежащую функцию.