Общая функция для сравнения двух целых чисел?
Существует ли стандартная функция 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
Если сайт вызова имеет доступный размер, я бы предпочел использовать его в качестве индекса в справочной таблице, чтобы сразу вызвать надлежащую функцию.