C++ Biginteger effizienter machen

Miuwa schrieb:
Da du intern bereits einen vektor zur verwaltung der Daten nutzt kannst du einfach die default Copy/Move - Konstruktor/Assignemnt operatoren verwenden, die der Compiler automatisch für dich anlegt. Deine manuelle Implementierung ist also unnötig. Move ist übrigens auch das Standardverhalten für den Rückgabewert.

Diesem Thread hier http://stackoverflow.com/questions/4819936/why-no-default-move-assignment-move-constructor zufolge ist deine Behauptung nicht korrekt. Wenn ich das richtig verstanden habe, gibt es keinen compiler-generierten default-move-constructor für benutzer-definierte Typen.
Sehe ich das falsch?
Ergänzung ()

Okay, cppreference.com sagt was anderes

If the implicitly-declared move constructor is neither deleted nor trivial, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used. For union types, the implicitly-defined move constructor copies the object representation (as by std::memmove). For non-union class types (class and struct), the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument.

Allerdings müßte er den erst mit

Code:
BigInteger( BigInteger && ) = default;

enablen, da er per Default in seinem Fall wegen folgender Restriktionen nicht generiert würde:

If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:

there are no user-declared copy constructors
there are no user-declared copy assignment operators
there are no user-declared move assignment operators
there are no user-declared destructors
(until C++14) the implicitly-declared move constructor is not defined as deleted due to conditions detailed in the next section

then the compiler will declare a move constructor as an inline public member of its class with the signature T::T(T&&).


EDIT: Hmpf, nein müßte er nicht. Habe seine Klassen-Definition noch mal überprüft, und sie erfüllt automatisch alle Anforderugen für einen default move constructor.

@datalukas: Sorry dafür, deine Zeit verschwendet zu haben, aber wengistens haben wir beide was über move constructors gelernt. :p
 
Zuletzt bearbeitet:
Das heißt, die Klasse hätte auch so einen move constructor, der auch bei Anweisungen wie dieser verwendet würde?
Code:
Biginteger result = ( a + b ) * c;
 
datalukas schrieb:
Das heißt, die Klasse hätte auch so einen move constructor, der auch bei Anweisungen wie dieser verwendet würde?
Code:
Biginteger result = ( a + b ) * c;

Die Klasse hat den move constructor auf jeden Fall. Ob er in dieser Anweisung auch zum Einsatz kommt, müßtest du doch eigentlich recht einfach selbst überprüfen können, indem du testweise deine Biginteger-Klasse um eine Instanz folgende Klasse erweiterst.

Code:
class TestMovable
{
public:
	TestMovable( TestMovable&& other )
	{
		std::cout << "TestMovable move c'tor called (from instance: 0x" << std::hex << &other << ", to instance: 0x" << this << std::dec << ")\n";
	}

	TestMovable& operator = ( TestMovable&& other )
	{
		std::cout << "TestMovable move assigment operator called (from instance: 0x" << std::hex << &other << ", to instance: 0x" << this << std::dec << ")\n";
		return *this;
	}
};

Jedes mal, wenn eine dieser Ausschriften kommt, dann weißt du, daß auch der entsprechende Operator/Konstruktor der Biginteger-Klasse aufgerufen wurde.

P.S. Bin mir nicht sicher, ob du die TestMovable-Klasse eventuell noch mit einem Default-Konstruktor versorgen mußt, oder ob der trotzdem implizit generiert wird, auch wenn man einen eigenen Move-Konstruktor deklariert hat.
 
Zuletzt bearbeitet:
Ok, sie werden beide in meinem Beispiel verwendet. :)
Nur frage ich mich, warum bei mir immer das Ergebnis 4780 rauskommt (richtig wäre 4782):
Code:
#include "stdafx.h"
#include <iostream>
#include "Biginteger.h"


int _tmain(int argc, _TCHAR* argv[])
{
	vector<Biginteger> fibonacci(2);
	int counter = 0;
	fibonacci[0] = 1;
	fibonacci[1] = 1;
	while (fibonacci[1].getSize() < 1000)
	{
		fibonacci.push_back(fibonacci[1] + fibonacci[0]);
		fibonacci.erase(fibonacci.begin());
		counter++;
	}
	cout << counter;
	system("Pause");
	return 0;
}
 
Spontan würde ich sagen, das counter nur in der Schleife hochzählt, du aber bereits vor der Schleife die ersten beiden Fibonacci Zahlen vorgibst (die beiden Einsen sind ja auch bereits Bestandteil der Fibonacci Folge). Damit müsste counter entsprechend mit zwei initialisiert werden (ähnlich der Lösung von convexus, da initialisiert er nbr mit zwei)
 
Danke, das wars. ;)
Mal eine Frage nebenbei:
Gibt es eine einfache Möglichkeit, in Visual Studio Headerdateien einzubinden, ohne den komplizierten Weg einer statischen Bibliothek gehen zu müssen, also einfach jeweils Ordner mit Quellcode und Headern zu haben, die der IDE mitgeteilt werden und dann einfach durch #include "example.h" einzubinden. Da bekomme ich immer Linker-Errors, wenn ich die jeweiligen Dateien nicht in den Solution Explorer ziehe, auch wenn der Pfad unter "Additional Include Directories" eingetragen ist.
 
datalukas schrieb:
Gibt es eine einfache Möglichkeit, in Visual Studio Headerdateien einzubinden, ohne den komplizierten Weg einer statischen Bibliothek gehen zu müssen, also einfach jeweils Ordner mit Quellcode und Headern zu haben, die der IDE mitgeteilt werden und dann einfach durch #include "example.h" einzubinden. Da bekomme ich immer Linker-Errors, wenn ich die jeweiligen Dateien nicht in den Solution Explorer ziehe, auch wenn der Pfad unter "Additional Include Directories" eingetragen ist.

Wo er nach Headern zu suchen hat, kannst du ihm natürlich sagen (das hast du ja schon rausgefunden), aber wenn es Übersetzungseinheiten (.cpp's) gibt, die mit übersetzt werden müssen, dann kommst du leider nicht drumhin, die entweder als zu übersetztende Einheiten deinem Projekt hinzuzufügen oder sie als bereits kompilierte .libs hinzuzulinken.
Ergänzung ()

daemon777 schrieb:
Ich hab mir den Code jetzt nicht angeguckt, aber sollte das so sein, dann ist das doch sowieso die ineffizienteste Art eine Big-Integer-Klasse zu schreiben. Viel besser wäre es doch einen möglichst großen Datentyp zu nutzen, um dann nicht mehr so viel selbst rumrechnen zu müssen.

Kannst du darauf etwas genauer eingehen? Ich kann dir nicht ganz folgen.
 
Ich hab noch mal nebenbei, auch wenn es jetzt nicht mehr zu dem Thema direkt passt, eine Frage zu Problem 27:
Das ist eigentlich relativ einfach mit Bruteforce umzusetzen, aber irgendwie kommt bie mir nicht das richtige raus, sondern -60393 mit einer angeblichen Länge von 1011, obwohl ich nirgendwo einen Fehler finden konnte:
Code:
#include "stdafx.h"
#include <iostream>

using namespace std;

bool isPrime(int number)
{
	if (number % 2 == 0)
	{
		return 0;
	}
	for (int i = 3; i < number / 2; i += 2)
	{
		if (number % i == 0)
			return 0;
	}
	return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
	int n, max_primes = 0, product_of_coefficients;
	for (int a = -999; a < 1000; a++)
	{
		for (int b = -999; b < 1000; b++)
		{
			n = 0;
			while (isPrime(n*n + a*n + b))
				n++;
			if (n > max_primes)
			{
				max_primes = n;
				product_of_coefficients = a*b;
			}		
		}
	}
	cout << product_of_coefficients << " " << max_primes;
	system("Pause");
	return 0;
}
 
Such mal eine Liste mit negativen Primzahlen und vergleiche sie mit den Ergebnissen deiner isprime()-Funktion. Der Fehler müsste schnell auffallen.
 
Da brauch ich mir gar keine Liste mehr zu suchen, ist klar. ;)
Man, immer solche blöden Fehler.:freak:
 
Zurück
Oben