Potęgowanie dużych liczb

0

Witam napisałem algorytm potęgowania liczb:

 unsigned long long int potega(long long int liczba, long long int wykładnik)
{
	if(liczba==0)
	{
		return 0;
	}	
	if(wykładnik==0)
	{
		return 1;
	}
	if(wykładnik%2==0)
	{
		return (liczba*potega(liczba, (wykładnik/2)-1))*(liczba*potega(liczba, (wykładnik/2)-1));
	}
	return liczba*potega(liczba,wykładnik-1);
}

Jakiego typu danych użyć aby móc spotęgować 2^1000, o ile mniejsza jest złożoność obliczeniowa tego algorytmu od:

unsigned long long int potęga(long long int liczba, long long int wykładnik)
{
	if(wykładnik==0)
	{
		return 1;
	}
	else if(liczba==1)
	{
		return 1;
	}
	else if(liczba==0)
	{
		return 0;
	}
	return liczba*potęga(liczba, wykładnik-1);
} 
0

2^1000? :-D Nie ma takiego typu liczbowego. Zainteresuj się jakąś biblioteką do obsługi tzw. dużych liczb (np. gmp).

Po co Ci tak ogromne liczby? Zapewne robisz to źle™.

0

Możesz także zaimplementować własną arytmetykę.

0
adam_vip1 napisał(a):

... o ile mniejsza jest złożoność obliczeniowa tego algorytmu od ...
n/log(n) razy.
Pomijając fakt że 2^1000 nie zmieści się do long long wychodzi około 100 razy.

Z tym że jak słusznie zauważył @MarekR22 (czytaj komentarz) dotyczy to pierwszego pomysłu ale w sensownej realizacji.

0

Ja skombinowałem coś takiego za pomocą rozwiązywanego kiedyś zadanka ze spoja:

#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>

struct Para {
    std::string a,b;
};

std::string dodaj(Para para);
std::string pomnoz(Para para);

int main() {
	std::string one,two;
    std::cin >> one;
	std::cin >> two;
	
	Para p;
	p.a = one;
	p.b = two;
	
	std::cout << pomnoz(p);
}

void toArrayInt(std::string source, std::vector<int> & dest) {
    for(int i = 0; i < source.length(); i++) {
		char temp[2];
		temp[0] = source[i];
		temp[1] = 0;
		dest.push_back(atoi(temp));
	}
}
std::string dodaj(Para para) {
	int dalej = 0; //określa część dziesiętna podczas przepełnienia
	std::vector<int> tabA,tabB;
	std::string result = "";
	toArrayInt(para.a,tabA);
	toArrayInt(para.b,tabB);
	std::vector<int>::reverse_iterator itA = tabA.rbegin();
	std::vector<int>::reverse_iterator itB = tabB.rbegin();
	for(; itA != tabA.rend() || itB != tabB.rend();) {
		int suma;
		bool end = false; //true gdy jest to ostatnia iteracja pętli
		if(itA != tabA.rend() && itB != tabB.rend()) {
			suma = *itA + *itB + dalej;
			++itA;
			++itB;
		} else if(itB != tabB.rend()){
			suma = *itB + dalej;
			++itB;
		} else {
			suma = *itA + dalej;
			++itA;
		}	
		if(itA == tabA.rend() && itB == tabB.rend()) {
			end = true;
		} 
		//sprawdzam czy wyszła dwucyfrowa liczba
		int cyfra;
		cyfra = suma % 10;
		suma /= 10;
		if(suma != 0)
			dalej = 1;
		else
			dalej = 0;
		std::stringstream ss;
		ss << cyfra;
		ss << dalej;
		result.insert(result.begin(), ss.str()[0]);
		if(end && dalej) {
			result.insert(result.begin(), ss.str()[1]); //wtedy gdy to jest ostatnia iteracja pętli
		}
	}
	return result;
}

std::string pomnoz(Para para) {
	Para num;
	num.a = para.a;
	num.b = para.a;
	std::string wynikPary = dodaj(num);
	
	std::string licznik = "0";
	std::string akumulator = "0";
	bool state = false;
	while(para.b != licznik) {
		//musimy iterować whilem "wielgachna liczba dzielona na 2".
		if(state) {
			Para p;
			p.a = akumulator;
			p.b = wynikPary;
			
			akumulator = dodaj(p);
			state = false;
		}
		else {
			state = true;
		}
		
		Para p;
		p.a = licznik;
		p.b = "1";
		licznik = dodaj(p);
	}
	return akumulator;
}

NIe jest to w pełni działający program jest on w stanie pomnożyć nieskończenie wielką liczbę(podawaną pierwszą na wejściu) z drugą liczba maks 4 cyfrowa i w dodatku parzystą. Ja chcę tylko zilustrować metodę. Jak by ktoś poprawił ten kod to by szło mnożyć nieskończenie wielkie liczby(z potęgowaniem nie było by problemu). Główny błąd polega na tym iż w pętli while mam iterować bardzo dużą ilość raz(liczba ta jest w stringu) i nie mam pojęcią jak zrobić to wydajniej. W obecnej chwili mam stringa i za każdym obiegiem pętli dodaje do niego stringa "1" i później powrównuje stringi w warunku while jeśli są nierówne pętla ma iterować dalej.

0

Założę się, że tak naprawdę autor wątku che policzyć a^b mod c, http://edu.i-lo.tarnow.pl/inf/alg/001_search/0017.php#Wyznaczanie


edit: twój algorytm potęgowania jest kiepski (oba mają liniową względem wykładnika złożoność obliczeniową). Pierwszy mógłbyś poprawić by miał złożoność `o(ln wykładnik)`, gdybyś pozbył się podwójnej rekurencji. Ja wolę tak (zakładając, że wynik się mieści w typie `long long int`). ```cpp typedef unsigned long long int ullong;

ullong potega(ullong a, ullong x) {
if(a==0) {
if (x==0)
throw std::invalid_argument("potega: undefined value: 0 to 0 power");
return 0;
}
ullong result = 1;
while(x) {
if (x&1==1)
result = a;
x>>=1;
a
=a;
}
return result;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1