LINUX.ORG.RU

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

 , , ,


1

1

Нужно вычислить НОД для чисел имеющий размер до 10^18, long long недостаточно. Как работать с числами таких размеров? p.s. Требуется реализация исключительно средствами языка и STL. p.p.s. Заодно покритикуйте имеющийся код:

#include <iostream>

using namespace std;
typedef unsigned long long ULL;
// объявление переменных, которые понадобятся в функциях.
ULL N=0, M=0, res=0;
short D=0;
// вычисление чисел
ULL ch(ULL digits)
{
   ULL ch=0;
    for(ULL i=0;i<digits;i++)
    {
        ch*=10;
        ch+=D;
    }
    return ch;
}
// вычисление НОД
ULL f_NOD(ULL ch1, ULL ch2)
{
    ULL NOD=1 ;
    for (short i=2;i<10;i++)
    {
        while(ch1 % i == 0 && ch2 % i == 0) //пока имеется общее кратное число увеличиваем НОД
        {
            NOD *=i;
            ch1 /=i;
            ch2 /=i;
        }
    }
    return NOD;
}
// heh
int main()
{
    cin >> N >> M;
    cin >> D;
    cout << f_NOD(ch(N),ch(M)) << endl;
    return 0;
}


Последнее исправление: jkjkjirf (всего исправлений: 5)

написать свой класс, который будет хранить std::vector<char> или std::string, где каждый элемент массива - одна цифра от 0 до 9 и переоределить для него арифметические операции

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

Не, мне это не подходит. Нужно без сторонних библиотек... Скорее всего придется писать свой класс, как Torvus посоветовал. Ну или искать чью-то уже готовую реализацию.
p.s У меня + еще ограничения на скорость работы и объем используемой памяти...

jkjkjirf
() автор топика

Может быть прость использовать __int128?

#include <bits/stdc++.h>
using namespace std;

int main(){
	__int128 a = 36, b = 12;
	cout << int64_t(__gcd(a, b)) << endl;
	return 0;
}

anonymous
()

typedef unsigned long long ULL;

Я бы за это убивал.

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

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

unC0Rr ★★★★★
()

Это почему это не хватает? 18 446 744 073 709 551 615~=18*10^18

vromanov ★★★
()

int64_t это как раз до 10**18, даже немного больше, log(2**63, 10) ~= 18.97

mashina ★★★★★
()
Последнее исправление: mashina (всего исправлений: 1)

Проблема не в величине int64, а в алгоритме. Он находит делители только от 2 до 9, чего никто не гарантировал.

Обычно НОД находят алгоритмом Евклида

template<class T>
T gcd(T a, T b)
{
   return b == 0 ? a : gcd(b, a % b);
}

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

кстати, у постгреса можно подсмотреть C-only реализацию типа numeric

Зачем? Это тип для точной «десятичной» арифметики.

mashina ★★★★★
()
Последнее исправление: mashina (всего исправлений: 1)
Ответ на: комментарий от mashina

Зачем? Это тип для точной «десятичной» арифметики.

через numeric также выражается тип decimal. ну и просто для примера неплохой реализации

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

через numeric также выражается тип decimal.

Не также, а numeric и decimal один и тот же тип. Если хочется посмотреть как работают с большими целыми, то нужен GMP

mashina ★★★★★
()
Последнее исправление: mashina (всего исправлений: 1)
Ответ на: комментарий от mashina

Если хочется посмотреть как работают с большими целыми, то нужен GMP

согласен, но

Требуется реализация исключительно средствами языка и STL

Torvus
()

http://e-maxx.ru/algo/big_integer

Все просто и понятно, я в 16 лет осилил. Только как по мне они базу не правильную выбрали, ну то есть не оптимальную. Для 64 разрядной системы, лучшей базой будет 2^32.

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

согласен, но

Там можно нагрепать ссылки на алгоритмы gcd для больших чисел, если вдруг числа нужны больше 10**18

mashina ★★★★★
()

я не понимаю, чем тебе алгоритм Евклида не угодил o_O

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

Если уж писать длинку с char, почему бы тогда хранить не от 0 до 255?

работать с цифрами быстрее и удобнее чем с числами

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

работать с цифрами быстрее и удобнее чем с числами

не правда же. Это значительно больший гемор и тупо медленнее. Тем более байт это точно такая же «цифра»

mashina ★★★★★
()
Последнее исправление: mashina (всего исправлений: 1)
Ответ на: комментарий от mashina

Это значительно больший гемор и тупо медленнее

а ты попробуй написать алгоритм умножения таких чисел, и поймешь, что таки нет, не гемор и не медленнее

Тем более байт это точно такая же «цифра»

а вот тут не согласен не только я

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

а ты попробуй написать алгоритм умножения таких чисел, и поймешь, что таки нет, не гемор и не медленнее

попробовал. Для оптимальности «перемножают» 4-8 байтовыми числами. Там же, в документации GMP, можно найти описание этих алгоритмов и объяснение почему это быстрее. А в описании алгоритмов десятичной арифметики почему она значительно медленнее двоичных чисел. Хотя это и так очевидно.

а вот тут не согласен не только я

Только ты, там согласны со мной.

A digit is a type of symbol <...> used in combinations to represent numbers <...> in positional numeral systems. In a given number system <...> the number of digits required is always equal to the absolute value of the base.

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

А в описании алгоритмов десятичной арифметики почему она значительно медленнее двоичных чисел. Хотя это и так очевидно

моя вина, согласен. я имел ввиду быстроту реализации

Только ты, там согласны со мной.

ну если использовать числа 256-ичной системе счисления то да

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

моя вина, согласен. я имел ввиду быстроту реализации

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

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

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

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

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

Создатели первых компьютеров тоже так думали и ваяли десятичные АЛУ на лампах. Ненадолго же их хватило... двоичная система самая удобная для таких игрищ.

AIv ★★★★★
()

Может муму не мучить, взять готовое из openssl?

$ ./NOD $[2**61] $[2**62] NOD: 2305843009213693952

$ cat NOD.cpp #include <openssl/bn.h> #include <ctime> #include <time.h>

// man bn int main(int argc, char *argv[]) { BN_CTX *ctx = BN_CTX_new( );

BIGNUM *m = NULL; BIGNUM *n = NULL;

BIGNUM *nod = BN_new( );

BN_dec2bn(&m, argv[1]); BN_dec2bn(&n, argv[2]);

BN_gcd( nod, n, m, ctx );

char *NOD_str = BN_bn2dec( nod ); printf(«NOD: %s \n», NOD_str);

BN_free( n ); BN_free( m ); BN_free( nod );

BN_CTX_free( ctx ); return 0; }

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