LINUX.ORG.RU

Работа с большими числами

 


0

1

Добрый день
Мне нужно реализовать работу с большими числами, размером около 4096 бит. На чистом си. (без использования библиотек)
Прошу Вас помочь мне разобраться в принципе таких действий
Полагаю что следует создать структуру, описывающую число.

#define BYTE_CHAR_SIZE   (sizeof(unsigned char))  // размер char
#define BYTE_NUMBER_MAX_SIZE  (4096/BYTE_CHAR_SIZE)  // максимальное количество байт для представления числа
struct big_number
{
  unsigned short byte_count;  // количество занятых байт, для представления числа
  unsigned char big_number[BYTE_NUMBER_MAX_SIZE]; // память для хранения числа
};

big_number - представляю в виде char а не int , т.к. вчера пытался разобраться в принципах работы с такими числами. И в одной библиотеке прочёл, что используется char для избежания проблем с умножением и делением больших чисел.(к сожалению, не могу найти ни ту библиотеку, ни описание..)
Давайте разберём инкримент числа.
Как полагаю, мне нужно будет в цикле пройти byte_count байт числа &big_number
При этом делать так
unsigned shor sign_flag = 0;  // флаг, указывающий было ли переполнение
char *current_byte_ptr = &big_number; // текущий проверяемый байт
unsigned short tmp = 0; // хранение временного значения



/* Само действие инкримента */
tmp = *current_byte_ptr + 1; // сохранили в временную переменную, чтоб узнать было ли переполнение

/* Определяем, случилось ли переполнение */
if(tmp > BYTE_CHAR_SIZE) sign_flag = 1;  // переполнение произошло

/* Если произошло переполнение */
if(sign_flag == 1)
{
  /* Обработка по аналогии следующего байта и так, пока byte_count не станет равен 0 */
}

return;  // Окончание действий инкремента
Будет ли такой способ работать?
(возможно я просто логику действия не понимаю)
Далее интересует будет ли такой код (обработки *char) работать корректно на системах с разным порядком байт.


Как реализовывается сложение чисел? скажем мне нужно к какому-то числу, представленному struct big_number прибавить другое число struct big_number , к примеру 888888888889999999999999 , какой алгоритм действия должен быть?
Аналогичный вопрос относительно умножения и деления.
Заранее спасибо
(Библиотеки смотрел, не получилось разобраться, потому и задаю вопрос тут)

Deleted

курсач? :)

(Библиотеки смотрел, не получилось разобраться, потому и задаю вопрос тут)

таки проще разобраться

Harald ★★★★★
()

На чистом си. (без использования библиотек)

(Библиотеки смотрел, не получилось разобраться, потому и задаю вопрос тут)

Если срочно, то в Job.

sT331h0rs3 ★★★★★
()
Ответ на: комментарий от sT331h0rs3

Это не курсач.
И это не работа
Ожидаю что тут или частично ответят на мои вопросы, или порекомендуют хорошую статью или книгу, где подробно рассматривается данный вопрос.

Deleted
()

без использования библиотек

ССЗБ

#define BYTE_CHAR_SIZE (sizeof(unsigned char)) // размер char

ОК, библиотеки не нужны. А почему нельзя uint8_t?

Кстати, «размер char» равен 1 по определению.

if(tmp > BYTE_CHAR_SIZE) sign_flag = 1; // переполнение произошло

открой для себя константы из https://ru.wikipedia.org/wiki/Limits.h

И да, тут ты сравниваешь с 1, см. выше.

Будет ли такой способ работать?

в принципе будет, но медленно из-за char.

Как реализовывается сложение чисел?

сначала делаешь выравнивание, т.е. в маленькое число добавляешь 0, что-бы размер был одинаковый, потом складываешь начиная с мл. байта.

Аналогичный вопрос относительно умножения и деления.

аналогичный ответ. Только деление ты наверное не осилишь, т.к. плохо учился в школе.

emulek
()
Ответ на: комментарий от Deleted

Искусство программирования. Том 2. Получисленные алгоритмы. Глава №4.

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

Можно ещё поглядеть в код GMP.

xaizek ★★★★★
()
Ответ на: комментарий от emulek

«аналогичный ответ. Только деление ты наверное не осилишь, т.к. плохо учился в школе.»
Что есть, то есть...
Значения limits мне не нужны...
«сначала делаешь выравнивание, т.е. в маленькое число добавляешь 0, что-бы размер был одинаковый»
Не понял, какое выравнивание получается?

Deleted
()
Ответ на: комментарий от emulek

да, умножение можно делать от младших и от старших, как больше нравится. Если у тебя в unsigned char'е 8 бит, то можно умножать сразу по 4 бита за раз, переполнения не будет, ибо 15*15=225.

Деление делается вычитанием, по одному биту за итерацию. Остаток можно не восстанавливать(кроме последнего раза, истинный остаток всегда ≥0).

emulek
()
Ответ на: комментарий от Deleted

насчёт сложения - эффективнее всего использовать ассемблерную инструкцию adc, сложение с учётом флага переноса

Младшие 4/8 байт складываются с помощью add, остальные - adc

В GMP наверняка именно так сделано

Harald ★★★★★
()
Ответ на: комментарий от Deleted

Значения limits мне не нужны...

тебе не нужны твои велосипеды с квадратными колёсами вроде BYTE_CHAR_SIZE.

Не понял, какое выравнивание получается?

например

123+7 → 0123+0007
emulek
()
Ответ на: комментарий от Harald

насчёт сложения - эффективнее всего использовать ассемблерную инструкцию adc

неправильно. Лучше SSE.

Ну можно FPU заюзать, он с целыми тоже умеет, если верить Intel и если числа меньше 2^64, и если есть тип long double (80и битный).

emulek
()
Ответ на: комментарий от xaizek

xaizek
Спасибо за книгу, уже смотрю.

Deleted
()

Ребят, давайте не вдаваться в ассемблер
А то сейчас дойдёт до специалезированных устройств где по 4096 разрядов на регистр.

Как понимаю с самого начала, я смысл действий понимал правильно. Сложение побайтово, с переносом. Насчёт деления, умножения, сдвигов и тд. видимо придётся как обычно самому разбираться.

Deleted
()
Ответ на: комментарий от Deleted

Сложение побайтово, с переносом

побайтово неэффективно, надо по размеру регистра, т.е. 4 или 8 байт в зависимости от архитектуры

Harald ★★★★★
()
Ответ на: комментарий от emulek

насчёт сложения - эффективнее всего использовать ассемблерную инструкцию adc

неправильно. Лучше SSE.

Это личный опыт или пальцем в небо? Когда это в SSE завезли сложение с переносом?

i-rinat ★★★★★
()
Ответ на: комментарий от Harald

По размеру регистра, эт хорошо конечно. А как мне тогда отследить , какое переполнение произошло? скажем я складываю 4294967296 и 4294967295. Как хранить результаты?

Deleted
()
Ответ на: комментарий от Harald

Хорошая идея. Спасибо за помощь. Попробую.

Deleted
()
Ответ на: комментарий от i-rinat

Когда это в SSE завезли сложение с переносом?

перенос можно эмулировать, это не долго для 128и битных чисел.

И большинство времени тратится не на сложение, а на умножение. Причём собственно частичное умножение можно делать параллельно (а потом складывать частичные произведения).

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

emulek
()

(Библиотеки смотрел, не получилось разобраться, потому и задаю вопрос тут)

google gnu gmp example спасет отца русской демократии.

Deleted
()
Ответ на: комментарий от Deleted

Насчёт деления, умножения, сдвигов и тд. видимо придётся как обычно самому разбираться.

А ты думал, тебе готовый код тут выложат?

four_str_sam
()
Ответ на: комментарий от i-rinat

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

emulek
()
Ответ на: комментарий от Deleted

Как понимаю с самого начала, я смысл действий понимал правильно. Сложение побайтово, с переносом. Насчёт деления, умножения, сдвигов и тд. видимо придётся как обычно самому разбираться.

детка, эти все правила мой сын сейчас старательно изучает. Он во втором классе учится. Ты спрашивай, я тебе всё объясню.

emulek
()
Ответ на: комментарий от emulek

внешний долг США считать, простые числа находить, число пи с точностью до 100500 знака вычислять и прочая мастурбация :)

Harald ★★★★★
()
Ответ на: комментарий от emulek

раз ты такой специалист

Я не специалист. Просто объём моих знаний о SIMD в x86 уже не позволяет мне с такой лёгкостью придумывать небылицы, как тебе. Перенос вообще плохо в идеологию SIMD вписывается, цель у них не та. Сложение с насыщением — да, а с переносом — нет. Вот скажи, зачем может понадобиться сложение значений двух пикселей с переносом из зелёного в красный? Или, скажем, зачем переносить бит из одной пары семплов звука в другую, а текущую «проворачивать»?

i-rinat ★★★★★
()
Ответ на: комментарий от Deleted

Какие правила? о чём ты?

facepalm

как «в столбик» вычислять. Чему вас только в школе-то учат?

emulek
()

Какие библиотеки смотрел?

У тебя по сути только один вариант разобраться с библиотеками.

И да, если можно, то лучше заюзай Python или Go.

deterok ★★★★★
()
Ответ на: комментарий от i-rinat

Перенос вообще плохо в идеологию SIMD вписывается

это очевидно, перенос ведь последовательно работает. Пока ты перенос не сгенеришь, считать нельзя.

Сложение с насыщением — да, а с переносом — нет.

не забывай про умножение. В 32х битной архитектуре ты 128и битный результат умножения получишь за 4 приёма, а в 128и битном sse2 всего за одну операцию. А умножение намного дороже и его сложность зависит пропорционально квадрату числа бит. И умножение на практике встречается примерно также, как сложение.

emulek
()
Ответ на: комментарий от emulek

не забывай про умножение. В 32х битной архитектуре ты 128и битный результат умножения получишь за 4 приёма, а в 128и битном sse2 всего за одну операцию.

Вот, теперь я ясно вижу, что ты меня троллишь.

его сложность зависит пропорционально квадрату числа бит

Ну точно троллишь.

i-rinat ★★★★★
()
Ответ на: комментарий от deterok

Смотрел gmp-6.0.0
Но сейчас стараюсь своими силами, принцыпы понять..потихоньку код пишу.
i-rinat
Хреновый из него троль.

Deleted
()
Ответ на: комментарий от i-rinat

ты так и не ответил на мой вопрос, я повторю:

где такие числа нужны? В смысле с любой разрядностью, а не фиксированные, вроде 2048и битных.

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

emulek
()
Ответ на: комментарий от Deleted

Лучше возьми готовое. И это, я тоже когда-то рвался все написать, вот теперь набравшиьс опыта могу сказать, что это не лучший вариант :)

deterok ★★★★★
()
Ответ на: комментарий от emulek

ты так и не ответил на мой вопрос «где такие числа нужны?»

Ответил. Я понятия не имею, где такие числа нужны.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

ну значит они не нужны. Я уже это вопрос на ЛОРе задавал, ответа нет.

А как оптимизировать «не нужно» на SSE2, я думаю рассуждать не нужно.

emulek
()
Ответ на: комментарий от emulek

И большинство времени тратится не на сложение, а на умножение. Причём собственно частичное умножение можно делать параллельно (а потом складывать частичные произведения).

Если нормально делать, то никто так в столбик большие числа не умножает.

Waterlaz ★★★★★
()
Ответ на: комментарий от emulek

А умножение намного дороже и его сложность зависит пропорционально квадрату числа бит.

нет, там n * log n или около того, где n — количество бит

Waterlaz ★★★★★
()

Новый вопрос появился!
Как вывести большое число в десятичном виде ? Есть буфер, размером примерно 256 байт, в нём хранится представление числа. Какой алгоритм вывода хранимого значения в десятичном виде на экран?

Deleted
()
Ответ на: комментарий от Waterlaz

Если много нужно переводить из 10-й и обратно, то подумай над тем, чтобы использовать 10000-ю систему или там 1000000000-ю =)

Waterlaz ★★★★★
()
Ответ на: комментарий от Waterlaz

Если много нужно переводить из 10-й и обратно, то подумай над тем, чтобы использовать 10000-ю систему или там 1000000000-ю =)

это не нужно. Переводить нужно только на входе/выходе.

emulek
()
Ответ на: комментарий от emulek

алгоритм давай уже.

Ты это серьезно?

Представляешь числа в виде многочленов.

542 = 5*x^2 + 4*x + 2

66 = 6*x + 6

Умножаешь многочлены(БПФ -> вычисление значений многочленов в комплексных корнях диницы -> перемножение значений -> обратное БПФ).

Делаешь сдвиги.

Профит.

Waterlaz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.