Pregunta Función genérica para comparar dos enteros?


¿Hay una función C (Linux) bastante estándar, o un enfoque eficiente en cuanto a los códigos, pero de buen rendimiento, para comparar dos enteros de un tamaño arbitrario?

Estoy buscando algo con los parámetros int intcmp(const void *a, const void *b, size_t size) eso funciona en enteros a y b para cualquier tamaño práctico size. (memcmp() funcionaría (creo) si la arquitectura fuera big endian.)

La implementación que suelo usar es la siguiente (con mejoras de Eficiente función de comparación de enteros) pero no es completamente genérico y tiene una sobrecarga de código suficiente como para pensarlo dos veces antes de asignarlo.

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

13
2018-05-13 05:39


origen


Respuestas:


Las funciones en línea estáticas tienen la ventaja de que los argumentos se evalúan solo una vez (esto es difícil / imposible de hacer con las macros). Esto permitiría llamadas de función como 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
2018-05-26 10:18



Si realmente necesita una buena comparación de números enteros de tamaños arbitrarios, le recomiendo que mire La Biblioteca de Aritmética de Precisión Múltiple de GNU. Eso requiere que uses su tipo especial mpz_t (que tiene la longitud incluida). Entonces puedes usar la función int mpz_cmp(mpz_t op1, mpz_t op2). Decidir sobre su propia representación de enteros grandes e implementarlo de forma que sea bastante portátil y eficiente no es trivial.

Si, por otro lado, solo necesitas los tamaños enteros estándar que mencionas, creo que tu implementación está bien. Pero para una portabilidad aún mejor, no debes hacer suposiciones sobre los distintos tamaños enteros:

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

Tal vez sea mejor crear una función separada para cada longitud que necesite en lugar de usar la misma para todos. Y finalmente, si la eficiencia es importante, a menudo es menos eficiente hacer aritmética con carbonizarse o corto que con En t. Intente evitar los casos en los que necesite llamar a esta función con char o short y use int en su lugar.


1
2018-05-26 05:53



Creo que el siguiente enlace ayudará. Realiza la comparación sin usar comparadores, lo que reduce un poco la sobrecarga de su código. He utilizado el código asociado con este enlace yo mismo en el pasado.

-Buena caza-

C programa para comparar enteros sin usar operadores lógicos?


0
2018-05-13 14:56



Si el sitio de llamadas tiene el tamaño disponible, preferiría usarlo como un índice en una tabla de búsqueda allí, para simplemente llamar a la función adecuada de inmediato.


0
2018-05-13 15:00