Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.83/40: Рейтинг темы: голосов - 40, средняя оценка - 4.83
2 / 2 / 2
Регистрация: 10.12.2015
Сообщений: 131

Длинная арифметика: деление с остатком двух чисел, находящихся в двусвязном списке

03.05.2017, 14:10. Показов 8121. Ответов 35
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток.
Подскажите, как реализовать деление с остатком двух чисел, находящихся в двусвязном списке, узлы которого - цифры.
Оба числа - положительные.

Первое что пришло в голову - пока число x меньше числа y
Производить умножение y на i, и увеличивать i на единицу.
Когда же будет больше - отнять от получившегося исходный x.
Но вот с реализацией как-то всё очень плохо..

P.S.
Использовать шаблоны - нельзя.
ООП - тоже.
Вообще, по заданию нужно найти НОД. Я же взял алгоритм с вычитанием. В итоге числа 99999999999 и 9 по понятным причинам считает очень долго.
Если можно как-то улучшить мою уже реализованную идею - буду благодарен.

Нужны только идеи
За ранее благодарен
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
03.05.2017, 14:10
Ответы с готовыми решениями:

Длинная арифметика, деление чисел
https://www.cyberforum.ru/attachment.php?attachmentid=393890&stc=1&d=1398936287 Помоги с решием , желательно код.Заранее спасибО!

Длинная арифметика. Реализовать деление и умножение целочисленных чисел
Добрый день. Нужно реализовать деление и умножение целочисленных чисел Читал http://e-maxx.ru/algo/big_integer , деление длинного на...

Сложение двух чисел (длинная арифметика)
Нужно реализовать длинную арифметику (сложение двух больших чисел), но на экран выводятся не понятные символы. Я подозреваю, что a =...

35
2 / 2 / 2
Регистрация: 10.12.2015
Сообщений: 131
06.05.2017, 18:27  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от GoldenId Посмотреть сообщение
Можете умножать и делить на основание Вашей системы счисления, но это более дорогая по времени операция.
Ну, для сдвигов я просто убираю из списка какой-то элемент.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
LongNumber * Mod(LongNumber *A, LongNumber *B)
{
    LongNumber *Reminder = (LongNumber *)malloc(sizeof(LongNumber));
    LongNumber *Devider = (LongNumber *)malloc(sizeof(LongNumber));
    memcpy(Reminder, A, sizeof(LongNumber));
    memcpy(Devider, B, sizeof(LongNumber));
    int shifts = 1;
    LongNumber *Quot =(LongNumber *) malloc(sizeof(LongNumber));
    Quot->Head = Quot->Tail = 0;
    Quot->size = 0;
    LongNumber *Add = (LongNumber *)malloc(sizeof(LongNumber));
    Add->Head = Add->Tail = NULL;
    Add->size = 0;
    AddDigit(Add, 1);
 
    while (MoreThen(Reminder, Devider))
    {
        LeftShift(Reminder);
        LeftShift(Add);
        shifts++;
    }
    while (shifts)
    {
        while (MoreThen(Devider, Reminder))
        {
            Reminder = Minus(Reminder, Devider);
            Quot = LongSumLong(Quot, Add);
        }
        RightShift(Devider);
        RightShift(Add);
        shifts --;
    }
    return Reminder;
}
В общем сделал по вашему "шаблону" но увы.
0
 Аватар для GoldenId
142 / 143 / 64
Регистрация: 11.11.2010
Сообщений: 877
Записей в блоге: 10
06.05.2017, 18:45
Цитата Сообщение от Teratore Посмотреть сообщение
Ну, для сдвигов я просто убираю из списка какой-то элемент.
Вам разрядов хватает для представления числа?
Что
Цитата Сообщение от Teratore Посмотреть сообщение
увы
-то?
0
2 / 2 / 2
Регистрация: 10.12.2015
Сообщений: 131
06.05.2017, 18:52  [ТС]
Цитата Сообщение от GoldenId Посмотреть сообщение
Вам разрядов хватает для представления числа?
Я не совсем понимаю про сдвиги.
Есть Add равный единице. Сдвигаю его влево. При сдвиге влево, число Add становится равно нулю? ( 1<<) = 0. Последующий сдвиг еще добавляется разряд?? И получается 00 я правильно понимаю?
Мне не понятно, при сдвигах нули добавляются или просто из числа убирать разряды.
0
 Аватар для GoldenId
142 / 143 / 64
Регистрация: 11.11.2010
Сообщений: 877
Записей в блоге: 10
06.05.2017, 19:06
Цитата Сообщение от Teratore Посмотреть сообщение
Есть Add равный единице. Сдвигаю его влево. При сдвиге влево, число Add становится равно нулю?
Нет. Если Вы сдвигаете влево число в двоичной системе счисления, то это равносильно его умножению на 2: 1 << 1 == 2. Если у Вас десятичные цифры, то сдвиг влево на 1 цифру равносилен умножению на 10.

Цитата Сообщение от Teratore Посмотреть сообщение
Последующий сдвиг еще добавляется разряд?? И получается 00 я правильно понимаю?
Зависит от того, как у Вас работают другие операции. Если они умеют обрабатывать числа с разным количеством разрядов, то не надо.

Цитата Сообщение от Teratore Посмотреть сообщение
Мне не понятно, при сдвигах нули добавляются или просто из числа убирать разряды.
Умеют у Вас другие операции обрабатывать числа с разным количеством разрядов?

Добавлено через 5 минут
Кроме того, обратите внимание, что у меня в while (1) сравнение строгое, а в (2) нестрогое.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Деление a / b
 
quot = 0;    // частное
rem = a;    // остаток
sub = b;
add = 1;
shifts = 1;
while( sub < rem ) // (1)
{
    sub <<= 1;    // сдвиг на 1 цифру
    add <<= 1;    // сдвиг на 1 цифру
    shifts++;
}
 
while( shifts )
{
    while( rem >= sub ) // (2)
    {
        rem -= sub;
        quot += add;
    }
    sub >>= 1;    // сдвиг на 1 цифру
    add >>= 1;    // сдвиг на 1 цифру
    shifts--;
}
1
2 / 2 / 2
Регистрация: 10.12.2015
Сообщений: 131
06.05.2017, 19:09  [ТС]
Цитата Сообщение от GoldenId Посмотреть сообщение
Зависит от того, как у Вас работают другие операции. Если они умеют обрабатывать числа с разным количеством разрядов, то не надо.
Складывать числа и вычитать числа с разным кол-вом разрядов - можно.
В обоих случаях от большего отнимается меньшее.
Если на вход поступает вначале меньшее, а потом большее - то делаю swap.
Цитата Сообщение от GoldenId Посмотреть сообщение
Если у Вас десятичные цифры, то сдвиг влево на 1 цифру равносилен умножению на 10.
Хорошо, операция умножения у меня есть. Хотя наверное проще будет добавлять ноль в конец. Со сдвигом в право тоже проблем быть не должно, просто отбросить цифру одну. Сейчас буду пробовать.
Цитата Сообщение от GoldenId Посмотреть сообщение
Кроме того, обратите внимание, что у меня в while (1) сравнение строгое, а в (2) нестрогое.
Хорошо, учту. Здесь самое главное разобраться с памятью, ибо исключения из-за обращения к NULL выскакивают.
0
 Аватар для GoldenId
142 / 143 / 64
Регистрация: 11.11.2010
Сообщений: 877
Записей в блоге: 10
06.05.2017, 19:11
Вы говорите, числа храните списками цифр
Цитата Сообщение от Teratore Посмотреть сообщение
memcpy(Reminder, A, sizeof(LongNumber));
* * memcpy(Devider, B, sizeof(LongNumber));
Если так, это скорее всего значения чисел не скопирует, а скопирует указатели на списки, в результате чего при изменении Reminder и Devider изменят и A и B. Вы принципиально избегаете возможностей C++?
0
2 / 2 / 2
Регистрация: 10.12.2015
Сообщений: 131
06.05.2017, 19:14  [ТС]
Цитата Сообщение от GoldenId Посмотреть сообщение
Вы принципиально избегаете возможностей C++
Нельзя к сожалению.

Цитата Сообщение от GoldenId Посмотреть сообщение
а скопирует указатели на списки,
Да, действительно..
0
 Аватар для GoldenId
142 / 143 / 64
Регистрация: 11.11.2010
Сообщений: 877
Записей в блоге: 10
07.05.2017, 11:24
Цитата Сообщение от Teratore Посмотреть сообщение
Хорошо, операция умножения у меня есть. Со сдвигом в право тоже проблем быть не должно, просто отбросить цифру одну.
При сдвиге влево - добавьте младшую цифру, равную нулю, при сдвиге вправо - выбросите младшую цифру.

Добавлено через 15 секунд
Вообще, в стиле разделения ответственности, было бы написать например функции:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* (1) */
LongNumber* makeEmptyNumber()
{
    LongNumber* res = (LongNumber *)malloc(sizeof(LongNumber));
    res->Head = res->Tail = 0;
    res->size = 0;
    /* инициализировать все другие нуждающиеся в этом члены res */
    return res;
}
 
/* (2) */
LongNumber* makeCopy( LongNumber* num )
{
    LongNumber* res = (LongNumber *)malloc(sizeof(LongNumber));
    /* скопировать все статические данные из num в res */
    for( /* каждая цифра в num*/ )
        /*создать копию этой цифры и поместить в res; */
    /* скопировать все другие динамически выделенные данные из num в res */
    return res;
}
 
/* (3) */
void dispose( LongNumber* num )
{
    for( /* каждая динамически выделенная цифра в num */ )
        /* освободить динамически выделенную под цифру память */
    /* освободить всю другую динамически выделенные под num память */
    free( num );
}
Это будут аналоги (1) конструктора по умолчанию, (2) конструктора копирования и (3) деструктора в функциональном программировании. Они разгрузят Вашу оперативную память от возни с группой копирования для решения Вашей задачи.
1
2 / 2 / 2
Регистрация: 10.12.2015
Сообщений: 131
07.05.2017, 14:08  [ТС]
Цитата Сообщение от GoldenId Посмотреть сообщение
Это будут аналоги (1) конструктора по умолчанию, (2) конструктора копирования и (3) деструктора в функциональном программировании. Они разгрузят Вашу оперативную память от возни с группой копирования для решения Вашей задачи.
Хорошо. Спасибо, тут понял.

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
LongNumber * Mod(LongNumber *A, LongNumber *B)
{
    LongNumber *Reminder = CopyDin(A);
    LongNumber *Devider = CopyDin(B);
    LongNumber *Quot = makeEmptyNumber();
    LongNumber *Add = makeEmptyNumber();
    AddDigit(Add, 1);
    int shifts = 1;
 
    while (Compare(Reminder, Devider) == 1)
    {
        LeftShift(Devider);
        LeftShift(Add);
        shifts++;
    }
    while (shifts)
    {
        while (Compare(Reminder, Devider) != -1)
        {
            Minus(Reminder, Devider);
 
            Quot = LongSumLong(Quot, Add);
        }
        RightShift(Devider);
        RightShift(Add);
        shifts --;
    }
    return Reminder;
}
Вот что на данный момент. При вводе 121 и 4 - возвращает 3 в качестве остатка. При вводе 101 и 2, как нужно - единица.
При вводе 100 и 2 (когда остатка нету) то зацикливается на
C
1
2
3
4
5
6
while (Compare(Reminder, Devider) != -1)
        {
            Minus(Reminder, Devider);
 
            Quot = LongSumLong(Quot, Add);
        }
Т.к. Reminder = Devider;

Я так понимаю что проблему нужно искать внутри моего сложения и вычитания.
Насколько плохо, что при вычитании A и B, я конечный результат записываю в A?
И то, что если A < B, я делаю их swap?

Ну и аналогично со сложением.
0
 Аватар для GoldenId
142 / 143 / 64
Регистрация: 11.11.2010
Сообщений: 877
Записей в блоге: 10
07.05.2017, 14:39
Цитата Сообщение от Teratore Посмотреть сообщение
Насколько плохо, что при вычитании A и B, я конечный результат записываю в A?
Аналог оператора -=. Здесь подходит.
Цитата Сообщение от Teratore Посмотреть сообщение
И то, что если A < B, я делаю их swap?
Здесь не должно играть роли. Если Вам сказано, что числа у Вас только неотрицательные, то при вычитании большего из меньшего - это UB. Не Ваша забота.

Цитата Сообщение от Teratore Посмотреть сообщение
Вот что на данный момент. При вводе 121 и 4 - возвращает 3 в качестве остатка. При вводе 101 и 2, как нужно - единица.
При вводе 100 и 2 (когда остатка нету) то зацикливается на
Посмотрите, правильно ли отрабатывают Minus, LongSumLong.
0
2 / 2 / 2
Регистрация: 10.12.2015
Сообщений: 131
07.05.2017, 14:54  [ТС]
Цитата Сообщение от GoldenId Посмотреть сообщение
Посмотрите, правильно ли отрабатывают Minus, LongSumLong.
Сложение я только что переписал, без swap и прочих не нужных вещей.
Вычитание если вызвать из main, и вычесть два числа - ровно как и сложение - работает.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
LongNumber * Minus(LongNumber *A, LongNumber *B)
{
    if (Compare(A, B) ==0) {
        LongNumber * Back = CreateEmptyNumber();
        AddDigit(Back, 0);
        return Back;
    }
    if (Compare(A,B) == -1)
        std::swap(A, B);
    Item * tempfirst = A->Head;
    Item * tempsecond = B->Head;
    while (tempfirst && tempsecond)
    {
        if (tempfirst->digit < tempsecond->digit)
        {
            Item * CurrentItem = tempfirst;
            CurrentItem->digit += 10;
            CurrentItem = CurrentItem->next;
            while (CurrentItem->digit <= 0)
            {
                CurrentItem->digit += 9;
                CurrentItem = CurrentItem->next;
            }
            CurrentItem->digit -= 1;
        }
        tempfirst->digit -= tempsecond->digit;
        tempfirst = tempfirst->next;
        tempsecond = tempsecond->next;
    }
    tempfirst = A->Tail;
    //Например: 106 - 104 = 002; 
    // Лишнии нули необходимо удалить.
    while (tempfirst)
    {
        if (tempfirst->digit != 0)
            break;
        //  if (tempfirst->prev == NULL)
    //          break;
        A->Tail = tempfirst->prev;
        A->Tail->next = NULL;
        free(tempfirst); // удаляем текущий элемент
        tempfirst = A->Tail; // делаем новую ссылку.
        A->size--;
    }
    return A;
}
P.S.
Если остаток равен нулю, зацикливания теперь - нету, всё хорошо, возвращает как и нужно - 0.
Но почему-то при делении по модулю 121 на 4, дает ответ 3.
Если просто вызвать minus в main при A = 12000000, B = 3 - всё хорошо. Если внутри Mod, то выбрасывает исключение.
0
 Аватар для GoldenId
142 / 143 / 64
Регистрация: 11.11.2010
Сообщений: 877
Записей в блоге: 10
07.05.2017, 15:31
Цитата Сообщение от Teratore Посмотреть сообщение
Но почему-то при делении по модулю 121 на 4, дает ответ 3.
Если вычитаете 40 из 121, сколько получается? Если 40 из 81? Если 40 из 41?

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
LongNumber * Deduct(LongNumber *A, LongNumber *B)
{
    LongNumber * res = CreateEmptyNumber();
    Item * tempfirst = A->Head;
    Item * tempsecond = B->Head;
    bool carry = false;
    while (tempfirst || tempsecond)
    {
        char digit = ( tempfirst ? tempfirst->digit : 0 ) - ( tempsecond ? tempsecond->digit : 0 ) - carry;
        if( digit < 0 )
        {
            carry = true;
            digit += 10;
        }
        else
            carry = false;
        
        добавить старшей цифрой digit в res
        
        tempfirst = tempfirst->next;
        tempsecond = tempsecond->next;
    }
    if (carry)
    {
        получили отрицательный результат - это переполнение, не Ваша забота
        можете добавить старшей цифрой к res единицу
    }
    tempfirst = res->Tail;
    //Например: 106 - 104 = 002; 
    // лидирующие нули необходимо удалить.
    while (tempfirst && tempfirst->digit == 0 && tempfirst != res->Head)
    {
        res->Tail = tempfirst->prev;
        res->Tail->next = NULL;
        free(tempfirst); // удаляем текущий элемент
        tempfirst = res->Tail; // делаем новую ссылку.
        res->size--;
    }
    return res;
}
0
2 / 2 / 2
Регистрация: 10.12.2015
Сообщений: 131
07.05.2017, 16:24  [ТС]
Цитата Сообщение от GoldenId Посмотреть сообщение
Если вычитаете 40 из 121, сколько получается? Если 40 из 81? Если 40 из 41?
Ну, отрицательные значения получаются.
Вообще, по заданию необходимо найти НОД. Собираюсь брать такой вариант:
C
1
2
3
4
while(m && n) {
if (m < n) n %= m;
 else m %= n;
} return m + n;
C
1
2
3
4
5
6
7
8
9
10
LongNumber * GCD2(LongNumber *A, LongNumber *B)
{
    while (!(IsZero(A) && IsZero(B)))
    {
        if (Compare(A, B) == -1)
            A = Mod(A, B);
        else B = Mod(B, A);
    }
        return LongSum(A,B);
}
Получается придется обрабатывать вариант, если A <B ??
0
 Аватар для GoldenId
142 / 143 / 64
Регистрация: 11.11.2010
Сообщений: 877
Записей в блоге: 10
07.05.2017, 17:26
Цитата Сообщение от Teratore Посмотреть сообщение
Сообщение от GoldenId
Если вычитаете 40 из 121, сколько получается? Если 40 из 81? Если 40 из 41?
Ну, отрицательные значения получаются.
Если вычитаете 40 из 121 должно получиться 81. Если вычитаете 40 из 81 должно получиться 41. Если вычитаете 40 из 41 должна получиться единица.
1
2 / 2 / 2
Регистрация: 10.12.2015
Сообщений: 131
07.05.2017, 19:27  [ТС]
Цитата Сообщение от GoldenId Посмотреть сообщение
Если вычитаете 40 из 121 должно получиться 81. Если вычитаете 40 из 81 должно получиться 41. Если вычитаете 40 из 41 должна получиться единица.
Моя функция Minus это умеет. (за счет swap)

В общем, извиняюсь что вам всё это время "выносил мозг"
Проблема оказалась в криво написаной мной функции копирования переменной. Оттуда и росли все проблемы.

Спасибо, что помогали, и в особенности за терпение. Теперь всё работает
0
 Аватар для GoldenId
142 / 143 / 64
Регистрация: 11.11.2010
Сообщений: 877
Записей в блоге: 10
07.05.2017, 20:08
Рад, что у Вас всё закончилось хорошо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
07.05.2017, 20:08

Длинная арифметика: операция сравнения двух чисел (A >= B)
Привет всем! помогите пожалуйста кодом. Необходимо реализовать операцию сравнения двух длинных чисел A&gt;=B Заранее спасибо

Длинная арифметика. Перемножение двух больших чисел
Насчет алгоритма выполнения не могу пока что сказать ничего. Дело в том, что после того, как ввожу первое число и нажимаю Enter, каретка...

Длинная арифметика. Вычитание двух положительных чисел
Доброго времени суток! У меня не получается сделать вычитание двух длинных положительных чисел... Пыталась разбираться по чужим кодам -...

Длинная арифметика: умножение двух длинных чисел
Всем привет! Снова к Вам за помощью. Алгоритм умножения двух длинных чисел: void...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
36
Ответ Создать тему
Новые блоги и статьи
Из невошедшего на форум (диалог с ИИ-гугла)
zorxor 29.07.2026
А вот, что интересно, сказал мне ИИ-гугла: Этот текст — эмоциональный пост пользователя под ником zorxor на интернет-форуме (вероятно, посвященном мистике, непознанному или альтернативной науке). . . .
Был праздник вчера, а я и не знал.
kumehtar 28.07.2026
27. 07. 2026г. Intel Core 2 Duo исполнилось 20 лет Новости компьютерного мира и их обсуждение (4) Салют, шампанское, овации! :drink:
Нейтральные знания, чистый код - бла-бла-бла-бла, на самом деле кликбейт и самореклама, плагиат, и вот почему
Hrethgir 27.07.2026
То-есть отклонение такой публикации говорит само за себя, и пусть только возьмут на вооружение после отклонения публикации - это будет чистейшим актом плагиата. Отклонял Хабр. Дословно, отклонённая. . .
тв 16 бой ии
anaschu 27.07.2026
Великий Перелом ИИ: Как уравнения ОДУ Radau дожали цензурные фильтры Алисы Фиксируем в мемофонде Теории Всего беспрецедентный факт в истории ИИ-зондирования. В затяжном многораундовом. . .
мв 15. непроверенное, возможно, глюк
anaschu 27.07.2026
НАУЧНО-АНАЛИТИЧЕСКИЙ ОТЧЕТ. РАЗДЕЛ 1. 1: «НАУКА» (РАСШИРЕННАЯ СТЕХИОМЕТРИЧЕСКАЯ И ГЕНЕТИЧЕСКАЯ ВЕРСИЯ)Тема: Теоретическое обоснование инвариантности 19-мерного тензорного ядра непрерывных ОДУ и. . .
Очистка реквизитов и табличных частей документа при копировании (вариант 2)
Maks 26.07.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРаботу", разработанного в КА2. Задача: Заменить алгоритм запрета копирования документов для сотрудников с ролью "Стажер",. . .
Доктрина интенционального знания - Доктрина для портала "Срез".
Hrethgir 25.07.2026
Может найдётся кто захочет оценить доктрину. . . Написания правил участия для меня роскошь, требующая лимита времени, поэтому все сообщения не прошедшие модерацию будут видны только участникам портала,. . .
сукцессия 44. Решил подать на припринт в межународные сервисы препринтов. Но нужно одобрение от ученых
anaschu 25.07.2026
Английский вариант. Пока кто то не одобрит мою личность, мне не получиться это опубликовать на препринте. Но заявку на публикацию статьи я сегодня подам.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru