Вопрос:

Как разделить два 64-битных числа в ядре Linux?

c linux 64-bit

8827 просмотра

4 ответа

0 Репутация автора

Некоторый код, который округляет деление для демонстрации (C-синтаксис):

#define SINT64 long long int
#define SINT32 long int

SINT64 divRound(SINT64 dividend, SINT64 divisor)
{
  SINT32 quotient1 = dividend / divisor;

  SINT32 modResult = dividend % divisor;
  SINT32 multResult = modResult * 2;
  SINT32 quotient2 = multResult / divisor;

  SINT64 result = quotient1 + quotient2;

  return ( result );
}

Теперь, если бы это было пространство пользователя, мы бы даже не заметили, что наш компилятор генерирует код для этих операторов (например, divdi3 () для деления). Скорее всего, мы связываемся с 'libgcc', даже не подозревая об этом. Проблема в том, что Kernel-space отличается (например, нет libgcc). Что делать?

Просканируйте Google на некоторое время и обратите внимание, что почти все обращаются к неподписанному варианту:

#define UINT64 long long int
#define UINT32 long int

UINT64 divRound(UINT64 dividend, UINT64 divisor)
{
  UINT32 quotient1 = dividend / divisor;

  UINT32 modResult = dividend % divisor;
  UINT32 multResult = modResult * 2;
  UINT32 quotient2 = multResult / divisor;

  UINT64 result = quotient1 + quotient2;

  return ( result );
}

Я знаю, как это исправить: переопределить udivdi3 () и umoddi3 () с помощью _do_div () _ из asm / div64.h . Сделано правильно? Неправильно. Signed - это не то же самое, что unsigned, sdivdi3 () _ не просто вызывает udivdi3 () , они являются отдельными функциями по определенной причине.

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

Спасибо чад

Автор: Chad Источник Размещён: 29.08.2008 11:22

Ответы (4)


0 плюса

985 Репутация автора

ldiv ?

Изменить: перечитать заголовок, так что вы можете игнорировать это. Или нет, в зависимости от того, имеется ли соответствующая небиблиотечная версия.

Автор: Mat Noguchi Размещён: 29.08.2008 11:31

4 плюса

188152 Репутация автора

Вот мое действительно наивное решение. Ваш пробег может варьироваться.

Держите знак бит, который есть sign(dividend) ^ sign(divisor). (Или *, или /, если вы храните свой знак как 1 и -1, в противоположность ложному и истинному. В основном, отрицательный, если один из них отрицательный, положительный, если ни один, или оба отрицательные.)

Затем вызовите функцию деления без знака на абсолютные значения обоих. Затем прикрепите знак обратно к результату.

PS Именно так и __divdi3реализовано libgcc2.c(из GCC 4.2.3, версии, которая установлена ​​в моей системе Ubuntu). Я только что проверил. :-)

Автор: Chris Jester-Young Размещён: 29.08.2008 11:45

0 плюса

0 Репутация автора

Я не думаю (по крайней мере, не могу найти способ заставить) ответ Криса работать в этом случае, потому что do_div () фактически меняет дивиденды на месте. Получение абсолютного значения подразумевает временную переменную, значение которой изменит способ, который мне требуется, но не может быть передан из моего переопределения __divdi3 () .

На данный момент я не вижу способа обойти сигнатуру параметра по значению __divdi3 (), кроме как для имитации техники, используемой do_div () .

Может показаться, что я наклоняюсь назад и должен просто придумать алгоритм для выполнения 64-битного / 32-битного деления, которое мне действительно нужно. Дополнительное усложнение здесь заключается в том, что у меня есть куча числового кода, использующего оператор «/», и мне нужно будет пройти через этот код и заменить каждый «/» вызовами моей функции.

Хотя я достаточно отчаялся, чтобы сделать это.

Спасибо за продолжение, Чад

Автор: Chad Размещён: 02.09.2008 04:06

4 плюса

165 Репутация автора

Эта функциональность представлена ​​в /linux/lib/div64.c еще в ядре v2.6.22.

Автор: colgur Размещён: 12.10.2008 09:52
Вопросы из категории :
32x32