View Full Version : [C++] assurdità
qualcuno mi saprebbe spiegare per quale assurdo motivo lo standard del C++ non ammette i tipi a virgola mobile come template parameters? :muro:
è una cosa completamente senza senso, del tutto immotivata: si tratta di una feature implementabilissima, tant'è che la Microsoft per aderire allo standard l'ha dovuta togliere da Visual C++ .NET, creando tra l'altro un breaking change.
Strùtrup è un c******e -.-'
marko.fatto
19-06-2008, 15:39
fìììco :asd:
^TiGeRShArK^
19-06-2008, 15:49
:rotfl:
W il C++ :O
:rotfl::rotfl::rotfl:
^TiGeRShArK^
19-06-2008, 15:50
fìììco :asd:
OT
ma non ti conveniva usare la tavolozza di colori ottimizzata piuttosto che il dithering nell'avatar? :stordita:
marko.fatto
19-06-2008, 15:55
OT
ma non ti conveniva usare la tavolozza di colori ottimizzata piuttosto che il dithering nell'avatar? :stordita:
mi sforava sempre nel peso :fagiano:
marko.fatto
19-06-2008, 15:57
scusate ma nell'esempio che c'è qui (http://www.cplusplus.com/reference/iostream/istream/read.html)
questo pezzo:
// allocate memory:
buffer = new char [length];
non dovrebbe essere:
// allocate memory:
buffer = new char [length+1];
per mettere anche il carattere di terminazione? :stordita:
DanieleC88
19-06-2008, 17:10
non dovrebbe essere:
// allocate memory:
buffer = new char [length+1];
per mettere anche il carattere di terminazione? :stordita:
No:
cout.write (buffer,length);
;)
qualcuno mi saprebbe spiegare per quale assurdo motivo lo standard del C++ non ammette i tipi a virgola mobile come template parameters? :muro:
è una cosa completamente senza senso, del tutto immotivata: si tratta di una feature implementabilissima, tant'è che la Microsoft per aderire allo standard l'ha dovuta togliere da Visual C++ .NET, creando tra l'altro un breaking change.
Suppongo sia dovuto al fatto che trattare in modo preciso con i floating point e' molto difficile, per cui c'e' il rischio concreto che cambiando anche solo i flag di compilazione vengano generati istanze di template diverse (immagina di fare delle operazioni con le SSE (64bit di precisione) invece che con la FPU (80)) e con rischi di bug subdoli.
Per inciso non mi viene in mente un esempio pratico di utilizzo di floating point come parametri template. Qualche idea ?
cdimauro
20-06-2008, 13:41
Una lista/stack/coda/lista doppiamente concatenata/ecc. di float?
Suppongo sia dovuto al fatto che trattare in modo preciso con i floating point e' molto difficile, per cui c'e' il rischio concreto che cambiando anche solo i flag di compilazione vengano generati istanze di template diverse (immagina di fare delle operazioni con le SSE (64bit di precisione) invece che con la FPU (80)) e con rischi di bug subdoli. uhm, :mbe: effettivamente questo ha senso...
Per inciso non mi viene in mente un esempio pratico di utilizzo di floating point come parametri template. Qualche idea ? quello che stavo cercando di fare io, ovvero una classe che rappresenta una generica costante matematica, come pi greco o la e. anziché fare una classe per ogni costante volevo fare un'unica classe templatizzata più una typedef per ogni costante: ciascuna typedef veniva definita al template con la rispettiva costante come argomento.
senza poter passare i numeri a virgola mobile come template parameters invece devo fare una classe base che contiene un campo double che è il valore della costante, e poi N classi derivate ciascuna delle quali chiama il costruttore protetto nella classe base passandogli la rispettiva costante. inoltre le N classi derivate hanno anche qualche altra specializzazione, per esempio ciascuna di esse ritorna il nome della costante ("pi", "e", ecc.).
Una lista/stack/coda/lista doppiamente concatenata/ecc. di float? non c'entra, in quel caso non passi un tipo float, passi un typename cioè il nome di un tipo; che può anche essere float. in altre parole non è questo che è vietato in C++:
list<float> ListOfFloatNumbers;
bensì questo:
template<float _Value>
class Constant
{
public:
// ...
};
...
Constant<M_PI> PI;
DanieleC88
20-06-2008, 14:33
quello che stavo cercando di fare io, ovvero una classe che rappresenta una generica costante matematica, come pi greco o la e.
Uhm, non è sufficiente descriverla come const float? Fare un template apposito cosa ti farebbe guadagnare? :wtf:
ilsensine
20-06-2008, 14:48
Suppongo sia dovuto al fatto che trattare in modo preciso con i floating point e' molto difficile, per cui c'e' il rischio concreto che cambiando anche solo i flag di compilazione vengano generati istanze di template diverse (immagina di fare delle operazioni con le SSE (64bit di precisione) invece che con la FPU (80)) e con rischi di bug subdoli.
Bè non credo, la precisione è un conto (e dipende dal processore), ma la dimensione è fissa per un dato compilatore. 64bit è double, 80 è long double, sulle nostre macchine.
Non capisco neanch'io questo limite però...
Uhm, non è sufficiente descriverla come const float? Fare un template apposito cosa ti farebbe guadagnare? :wtf: non l'ho descritta come const float perché si trattava di un programma per risolvere derivate e semplificare espressioni (se guardi un certo thread di qualche giorno fa capirai :asd: ), e quindi la costante deve costituire un tipo di espressione rappresentata come classe che risponda ad una certa interfaccia; nello specifico doveva avere un metodo Derive che calcola la derivata (cioè 0) e un metodo Simplify che resituisce this, più un po' di altra roba.
ne volevo fare un template perché così non dovevo scrivere una classe per ogni costante matematica usata.
Non capisco neanch'io questo limite però... io ho interpretato il discorso di marco.r in questa maniera; metti che uno scrive una cosa del genere:
template<float _Value>
class Floated
{
// ...
};
Floated<1> First;
Floated<1.0> Second;
Floated<2-1> Third;
...
non lo so mica se il compilatore genera sempre la stessa definizione... e in effetti non è comunque una buona abitudine per lo stesso motivo per il quale i confronti tra numeri a virgola mobile vanno evitati o fatti con un delta.
DanieleC88
20-06-2008, 15:44
Ah ok, non avevo capito quale fosse il tuo scopo. Be', in questo caso mi sembra più che giusto. Non avendo la possibilità di usare template, puoi pensare di salvare separatamente queste costanti? Così poi le tratti nei casi particolari quando derivi la formula o la semplifichi.
:)
Ah ok, non avevo capito quale fosse il tuo scopo. Be', in questo caso mi sembra più che giusto. Non avendo la possibilità di usare template, puoi pensare di salvare separatamente queste costanti? Così poi le tratti nei casi particolari quando derivi la formula o la semplifichi.
:)
alla fine ho fatto una cosa del genere:
class Expression
{
public:
virtual operator string () const = 0;
virtual Expression *Derive() = 0;
virtual Expression *Simplify() = 0;
};
class Constant : public Expression
{
public:
Expression *Derive();
Expression *Simplify();
};
class PI : public Constant
{
public:
operator string () const;
};
class E : public Constant
{
public:
operator string () const;
};
Expression *Constant::Derive()
{
// ritorna un'espressione che vale costantemente 0
}
Expression *Constant::Simplify()
{
return this;
}
PI::operator string () const
{
return "pi";
}
E::operator string () const
{
return "e";
}
(non è proprio questo il codice, semplifico)
mentre invece avrei voluto fare:
template<double _Value, const char *_Name>
class Constant : public Expression
{
public:
operator string () const
{
return _Name;
}
Expression *Derive()
{
// ritorna un'espressione che vale costantemente 0
}
Expression *Simplify()
{
return this;
}
};
typedef Constant<M_PI, "pi"> PI;
typedef Constant<M_E, "e"> E;
ilsensine
20-06-2008, 15:55
io ho interpretato il discorso di marco.r in questa maniera; metti che uno scrive una cosa del genere:
template<float _Value>
class Floated
{
// ...
};
Floated<1> First;
Floated<1.0> Second;
Floated<2-1> Third;
...
non lo so mica se il compilatore genera sempre la stessa definizione... e in effetti non è comunque una buona abitudine per lo stesso motivo per il quale i confronti tra numeri a virgola mobile vanno evitati o fatti con un delta.
No continuo a non vedere perché un float qui possa dare problemi.
Allora anche questo non va bene:
template<char _param>
class MrX [...]
in quanto può generare cose diverse a seconda dell'architettura e (sotto il gcc almeno) dei parametri di compilazione.
No continuo a non vedere perché un float qui possa dare problemi.
Allora anche questo non va bene:
template<char _param>
class MrX [...]
in quanto può generare cose diverse a seconda dell'architettura e (sotto il gcc almeno) dei parametri di compilazione.
che generi cose diverse a seconda dell'architettura va benissimo: chi se ne frega :D
mai sentito parlare di ABI mismatch? :Prrr:
DanieleC88
20-06-2008, 15:59
alla fine ho fatto una cosa del genere: [...]
Ottima soluzione, in effetti... dovrei esercitarmi di più con la OOP... :stordita:
Certo era più comodo (ed "elegante") con un template, ma finché funziona... :D
ilsensine
20-06-2008, 16:06
che generi cose diverse a seconda dell'architettura va benissimo: chi se ne frega :D
Eh peccato che puoi decidere con un flag di compilazione se char debba essere signed o unsigned...e una volta mi è servito...
Bè non credo, la precisione è un conto (e dipende dal processore), ma la dimensione è fissa per un dato compilatore. 64bit è double, 80 è long double, sulle nostre macchine.
Se non ricordo male i conti vengono comunque fatti dalla FPU a 80 bit, e troncati a 64 bit poi, o sbaglio :confused:. Se cosi' fosse, usare espressioni come parametri float potrebbe portare ad approssimazioni diverse in base a come viene compilato l'eseguibile. Anzi in base a come e' stato compilato il compilatore. Diciamo che e' lo stessa classe di problemi per cui non si confrontano mai numeri in virgola mobile per uguaglianza, solo che in questo caso il problema riguarderebbe la generazione del codice da parte del compilatore (Foo< 1.0 / M_PI > utilizza lo stesso codice di Foo< M_1_PI > ?) e probabilmente hanno considerato la fatica piu' grossa del guadagno.
Eh peccato che puoi decidere con un flag di compilazione se char debba essere signed o unsigned...e una volta mi è servito... infatti se tu linki assieme file oggetto compilati con opzioni diverse da quel punto di vista e con dei template parametrizzati con char, temo proprio che il tuo programma avrà dei bug :p
solitamente però un programma viene compilato coerentemente con se stesso, e le opzioni del compilatore e del linker in genere sono tutte identiche per tutti i file oggetto. poi, se esiste un altro programma compilato con una diversa impostazione per il segno dei char, e questi due programmi devono comunicare tra di loro tramite complesse interfacce C++ che fanno uso di templates, allora ci troveremo quasi sicuramente davanti a un bel caso di ABI mismatch. l'ABI mismatch non mi sembra tanto strano tra due programmi diversi, anche sulla stessa macchina.
ilsensine
20-06-2008, 16:18
infatti se tu linki assieme file oggetto compilati con opzioni diverse da quel punto di vista e con dei template parametrizzati con char, temo proprio che il tuo programma avrà dei bug :p
Lì veramente usavo una libreria che assumeva char=signed char, e ci venivano fatti dei calcoli. Ovviamente ho dovuto ricompilare libreria e chi ne faceva uso in quel modo.
solitamente però un programma viene compilato coerentemente con se stesso[...]
Certo, ho citato quel caso solo come controesempio alla ipotesi di marco.r:
Suppongo sia dovuto al fatto che trattare in modo preciso con i floating point e' molto difficile, per cui c'e' il rischio concreto che cambiando anche solo i flag di compilazione vengano generati istanze di template diverse
alla fine ho fatto una cosa del genere:
...
Non e' un tantino overkill ? :mbe:
Perche' non fare ricorso ad un semplice costruttore con argomenti ?
class Constant : public Expression
{
public:
Constant( float value, const std::string& name )
{ this->value = value, this->name = name; }
Expression *Derive();
Expression *Simplify();
operator string () const { return name; }
};
...
const Constant PI = Constant( M_PI , "pi" );
non vedo controindicazioni...
qualcuno mi saprebbe spiegare per quale assurdo motivo lo standard del C++ non ammette i tipi a virgola mobile come template parameters? :muro:
è una cosa completamente senza senso, del tutto immotivata: si tratta di una feature implementabilissima, tant'è che la Microsoft per aderire allo standard l'ha dovuta togliere da Visual C++ .NET, creando tra l'altro un breaking change.
Strùtrup è un c******e -.-'
Scusate ma non ho capito. Il C++permette questo:
Classe<float> a;
Ma non questo:
Classe<1.0> a;
state dicendo questo o sbaglio? E la precisione come mai dà fastidio solo nel secondo caso allora?
Non e' un tantino overkill ? :mbe:
Perche' non fare ricorso ad un semplice costruttore con argomenti ?
class Constant : public Expression
{
public:
Constant( float value, const std::string& name )
{ this->value = value, this->name = name; }
Expression *Derive();
Expression *Simplify();
operator string () const { return name; }
};
...
const Constant PI = Constant( M_PI , "pi" );
non vedo controindicazioni...
*
Scusate ma non ho capito. Il C++permette questo:
Classe<float> a;
Ma non questo:
Classe<1.0> a;
state dicendo questo o sbaglio? E la precisione come mai dà fastidio solo nel secondo caso allora?
perchè nel primo caso tratti un tipo di oggetto, non l'oggetto in se, quindi la precisione non c'entra nella gestione del template
Non e' un tantino overkill ? :mbe:
Perche' non fare ricorso ad un semplice costruttore con argomenti ?
class Constant : public Expression
{
public:
Constant( float value, const std::string& name )
{ this->value = value, this->name = name; }
Expression *Derive();
Expression *Simplify();
operator string () const { return name; }
};
...
const Constant PI = Constant( M_PI , "pi" );
non vedo controindicazioni... beh, :mbe: buh, boh, non vedo neanche vantaggi... m'era venuto in mente così e ho fatto così... come complessità mi sembra la stessa cosa.
Scusate ma non ho capito. Il C++permette questo:
Classe<float> a;
Ma non questo:
Classe<1.0> a;
state dicendo questo o sbaglio? non sbagli
E la precisione come mai dà fastidio solo nel secondo caso allora? perché questo
Classe<1.0f> a;
potrebbe generare un tipo diverso da questo:
Classe<1.0> a;
o da questo:
Classe<1> a;
in quanto 1.0f (numero di tipo float) potrebbe differire leggermente da 1.0 (numero double troncato a float) e da 1 (numero intero convertito a float); la stessa ragione percui non bisognerebbe mai confrontare due numeri a virgola mobile se non con un delta.
in quanto 1.0f (numero di tipo float) potrebbe differire leggermente da 1.0 (numero double troncato a float) e da 1 (numero intero convertito a float); la stessa ragione percui non bisognerebbe mai confrontare due numeri a virgola mobile se non con un delta.
Invece passare solo il tipo permette al compilatore di trattare tutto con la stessa precisione giusto? In tal caso eventuali errori di precisioni si equivarrebbero tra tutti i float generati da quel template e saremmo "pari". Almeno credo..
Invece passare solo il tipo permette al compilatore di trattare tutto con la stessa precisione giusto? In tal caso eventuali errori di precisioni si equivarrebbero tra tutti i float generati da quel template e saremmo "pari". Almeno credo.. se passi il tipo "float" come template parameter non crei nessun problema di precisione: non stai comparando nessun float... al massimo quel template parameter potrà essere usato nel template in punti dove è richiesto il nome di un tipo (dichiarazioni di variabili e parametri), non riesco ad immaginare come questo possa essere la causa di una comparazione tra numeri a virgola mobile.
cdimauro
21-06-2008, 10:44
Eh peccato che puoi decidere con un flag di compilazione se char debba essere signed o unsigned...e una volta mi è servito...
Ma non bastava che definissi tu, con un typedef, il tipo preciso che ti serviva?
Comunque non è lecito (non mi riferisco a te, ma a chi scritto quella libreria di cui parli dopo) assumere che un char sia signed o assigned: ci si lega mani e piedi al compilatore. Anzi, alla particolare implementazione del compilatore, visto che può benissimo cambiare.
Per curiosità: di che libreria si trattava?
Se non ricordo male i conti vengono comunque fatti dalla FPU a 80 bit, e troncati a 64 bit poi, o sbaglio :confused:. Se cosi' fosse, usare espressioni come parametri float potrebbe portare ad approssimazioni diverse in base a come viene compilato l'eseguibile. Anzi in base a come e' stato compilato il compilatore.
Questo avviene sicuramente quando si usa la vecchia FPU x87, e il valore del registro, solo in caso di store in memoria come double, viene troncato o arrotondato (a seconda dei relativi flag del registro di stato della FPU).
Per le SSE onestamente non ricordo se le operazioni vengono eseguite con 80 bit di precisione, per poi essere subito troncate o arrotondate.
Qui il workflow è un po' diverso da quello precedente, perché nei registri i dati vengono sempre conservati con lo stesso formato / spazio usato (quindi i double sono tenuti nei registri SSE esattamente come sono; mentre con la FPU x87 qualunque load "espande" eventualmente il dato per occupare tutti gli 80 bit), e ovviamente dopo l'operazione riportati sempre nello stesso formato.
Niente, non ricordo proprio se "in mezzo" le operazioni vengano eseguite a 80 bit di precisione, ma anche se fosse IMHO avrebbe poco senso (e si sprecherebbero transistor e cicli di clock in più inutilmente), perché in ogni caso i dati subiscono immediatamente un troncamento.
Diciamo che e' lo stessa classe di problemi per cui non si confrontano mai numeri in virgola mobile per uguaglianza,
Qui non sono d'accordo. Esistono casi in cui i float sono perfettamente confrontabili (se siamo fermamente coscienti di quali casi siano). Ad esempio quando rappresentano... degli interi. :p
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.