PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : F: float, double parameterübergabe als referenz überflüssig?


Chris Lux
2006-03-06, 10:41:55
hi,
nur eine kurze frage. ist folgendes unnötig oder gar kontraproduktiv?
hauptsächlich sollen float und double werte verwendet werden.

template<typename scalar>
inline scalar plah(const scalar& s)
{
// do some funky shit
}

Coda
2006-03-06, 10:46:30
Du meinst weil du es als Referenz übergibst? Ja ist kontraproduktiv.

Falls du noch andere (größere Datentypen) mit der Funktion benützen willst bietet es sich an das Template für float und double zu spezialisieren.

Chris Lux
2006-03-06, 11:01:42
Du meinst weil du es als Referenz übergibst? Ja ist kontraproduktiv.

welche nachteile entstehen durch das verwenden von referenzen? ein pointer/referenz sollte ja auch 32bit (bzw 64bit) sein. entsteht durch das dereferenzieren soviel overhead?

Coda
2006-03-06, 11:08:39
Ist die Frage wirklich ernst gemeint? Denk mal drüber nach.

Ich helf dir: Pod-Typen als const-Referenz übergeben ist Schwachsinn.

Chris Lux
2006-03-06, 11:21:10
Ist die Frage wirklich ernst gemeint? Denk mal drüber nach.
würde ich fragen?
mir geht es nur darum welcher nachteil entstehen kann.

Coda
2006-03-06, 11:23:35
Du verlierst unnötig Performance weil bei jedem Zugriff 2 statt einem Speicherzugriffe enstehen. Was erhoffst du dir denn bitte für Vorteile daraus?

Chris Lux
2006-03-06, 11:30:54
Du verlierst unnötig Performance weil bei jedem Zugriff 2 statt einem Speicherzugriffe enstehen. Was erhoffst du dir denn bitte für Vorteile daraus?
ok. das ist was ich wissen wollte. danke.

der vorteil wäre nur die allgemeinheit meine mathe lib gewesen. so könnte ich diese um selbst gebastelte typen recht einfach erweitern. werde jetzt aber die referenzen vermeiden.

Coda
2006-03-06, 11:38:05
#include <iostream>
#include <complex>

template<typename scalar> scalar plah(const scalar& s)
{
std::cout << "omg, values by reference" << std::endl;
return s;
}

inline float plah(float s)
{
std::cout << "it's teh float" << std::endl;
return s;
}

inline double plah(double s)
{
std::cout << "double!!111" << std::endl;
return s;
}

int main()
{
std::complex<float> foo(2.0,1.0);

plah(1.337);
plah(2.0f);
plah(foo);
}

Chris Lux
2006-03-06, 11:41:15
[...]
danke, aber ich weiss wie das funktioniert. es sind aber schon recht große funktionen, die keinen spass machen xmal zu implementieren. ich werde mich um die referenzübergabe kümmern, wenn sie gebraucht wird.

Coda
2006-03-06, 11:47:46
Du kannst ja eine do_plah funktion schreiben die das zeug ausführt. AFAIK bleibt eine Referenz eine Referenz wenn du sie an ein anderes template übergibst.

Wobei sich das nicht so einfach feststellen lässt, da selbst typeid() nicht zurückgibt ob ein Typ eine Referenz ist oder nicht.

Chris Lux
2006-03-06, 11:50:04
noch eine kleine frage. wie gut optimieren compiler folgendes:


class matrix; // lets say 16 floats

matrix get_special_matrix()
{
matrix tmp;

// fill up tmp

return (tmp);
}


wird hier jedesmal der copy contructor bei der rückgabe angeworfen? es gibt noch zwei wege, von denen ich den zwweiten nicht sehr mag (aber da ist die effizient am deutlichsten sichtbar;) )
variante 1

class matrix; // lets say 16 floats

matrix get_special_matrix()
{
return (matrix( /*put values here*/) );
}

variante 2

class matrix; // lets say 16 floats

void get_special_matrix(matrix &m)
{
// fill up m
}

Coda
2006-03-06, 11:57:05
Das sollte jeder Compiler rausoptimieren. ich mach das auch immer so (also mit temponärer Variable).

Und Sweeney macht es auch so ;) (gabs mal nen COTD auf Flipcode)

KiBa
2006-03-06, 22:06:40
das mit der temporären variable sollte für den compiler am einfachsten optimierbar sein. das hat auch einen speziellen namen: "named return value optimization", sprich, der rückgabewert wird direkt im ziel-wert konstruiert.

bei dem problem mit den referenzen sagt man ja immer, alles was kleiner gleich die größe von einem pointer ist, per value übergeben, sonst per (konstanter) referenz. double ist da schon grenzwertig, das müsste man mal durchtesten.
ansonsten würden zwei spezielisierungen der template funktionen reichen, je eine mit referenz-übergabe, die andere per value. dann kanst du z.b. mit boost::enable_if genau bestimmen, für welche typen was gilt. vielleichts gibts ja auch nen eleganteren weg ohne code-verdopplung...

Coda
2006-03-06, 22:20:46
double denke ich ist nicht grenzwertig, weil das auch oft einfach auf den FPU-Registerstack passt zum übergeben.

Und wenn man das Ding 2x verwendet in der Funktion dürfte selbst die Kopie schon günstiger sein.

Bietchiebatchie
2006-03-07, 12:39:08
Du verlierst unnötig Performance weil bei jedem Zugriff 2 statt einem Speicherzugriffe enstehen. Was erhoffst du dir denn bitte für Vorteile daraus?
Bist du dir 100% sicher, dass bei ner const-reference-Übergabe jeweils zwei Speicherzugriffe stattfinden? Afaik ist ne const-reference doch nur eine Anweisung, dass direkt auf den Daten gearbeitet werden soll, die übergeben werden...

Sowas geht ja

void blubb( const int& a)
{
// whatever
}

int main()
{
//...
blubb(1);
//...
}

wie sollen da jetzt zwei Speicherzugriffe zustande kommen? 1 ist nur nen Integer und hat keine Adresse im Speicher, kann folglich auch nicht dereferenziert werden.

del_4901
2006-03-07, 12:55:59
Bist du dir 100% sicher, dass bei ner const-reference-Übergabe jeweils zwei Speicherzugriffe stattfinden? Afaik ist ne const-reference doch nur eine Anweisung, dass direkt auf den Daten gearbeitet werden soll, die übergeben werden...

Sowas geht ja

void blubb( const int& a)
{
// whatever
}

int main()
{
//...
blubb(1);
//...
}

wie sollen da jetzt zwei Speicherzugriffe zustande kommen? 1 ist nur nen Integer und hat keine Adresse im Speicher, kann folglich auch nicht dereferenziert werden.

Alles hat ne Adresse.

void foo(type &a) ist nur synktaktischer Zucker für void foo(type *a) damit man nicht immer (*a).blah oder a->blah schreiben muss. Und durch die derefferenzierung kommt jeweils ein Befehl hinzu.

Neomi
2006-03-07, 13:15:23
Bist du dir 100% sicher, dass bei ner const-reference-Übergabe jeweils zwei Speicherzugriffe stattfinden? Afaik ist ne const-reference doch nur eine Anweisung, dass direkt auf den Daten gearbeitet werden soll, die übergeben werden...

Wie soll sowas sonst gehen? Eine Referenz ist ein Pointer, der automatisch dereferenziert wird. Bei Inline-Expansion wird das zwar meistens rausoptimiert, aber das Prinzip bleibt.

wie sollen da jetzt zwei Speicherzugriffe zustande kommen? 1 ist nur nen Integer und hat keine Adresse im Speicher, kann folglich auch nicht dereferenziert werden.

Da wird dann logischerweise ein Integer auf dem Stack angelegt und dessen dann vorhandene Adresse wieder über den Stack übergeben.

Coda
2006-03-07, 13:51:32
Es ist nirgends vorgeschrieben dass eine Referenz als Pointer implementiert werden muss, aber wenn das Ding nicht inline expandiert wird, ist es zu 99,999% der Fall.

Wenn man eine const-Referenz mit einem const-Pointer in einer Funktion austauscht dürfte das für den Compiler genau 0 Unterschied machen bei den Optimierungsmöglichkeiten.

Xmas
2006-03-07, 15:24:05
double denke ich ist nicht grenzwertig, weil das auch oft einfach auf den FPU-Registerstack passt zum übergeben.

Und wenn man das Ding 2x verwendet in der Funktion dürfte selbst die Kopie schon günstiger sein.
Ersteres stimmt, aber wie oft die Referenz verwendet wird dürfte keinen Unterschied machen.

Übergabe per FPU-Register ist natürlich am schnellsten, 8 Byte vom Speicher in den FPU-Stack lesen, die Funktion kann sie gleich verwenden.
Übergibt man double per Stack, werden 8 Byte geschrieben und gleich wieder gelesen, damit die Funktion den Wert verwenden kann.
Wird eine double-Referenz per Stack übergeben, werden bei 32-Bit-Pointern 4 Byte geschrieben, wieder gelesen, und damit ein double-Wert adressiert und gelesen. Danach hast du den Wert ja im FPU-Stack.