View Full Version : [C++] Valore dello static_cast sbagliato
Ho un problema in un programma dove avrei bisogno di troncare un double per assegnare la parte intera ad un int. In pratica mi arriva un numero fra 0 e 1, che rappresenta una percentuale, io voglio scriverla "normalmente" come numero fra 0 e 100, per cui moltiplico il numero che arriva per 100 e lo converto in int con lo static_cast, in questo modo:
f(double percentualeDiPartenza_, double percentualeMassima_) {
int minimo, massimo;
double percentualeDiPartenzaInCentesimi = percentualeDiPartenza_*100.0, percentualeMassimaInCentesimi = percentualeMassima_*100.0;
minimo = static_cast<int>(percentualeDiPartenzaInCentesimi);
massimo = static_cast<int>(percentualeMassimaInCentesimi);
}
A questo punto succede quello che non capisco: se il numero che devo convertire come percentuale massima è 0.1, il risultato in massimo è 9 anziché 10, in più questo succede solo dentro questo programma, ho provato a "isolare" il pezzo di codice in un programma diverso e stampa 10:
#include <iostream>
using std::cout;
using std::endl;
int main() {
int numero;
double numero2 = 0.1;
numero = static_cast<int>(numero2*100.0);
cout << numero << ' ' << numero2 << endl;
}
L'output che ho è:
10 0.1
Non riesco a capire se ho il prosciutto sugli occhi io e c'è qualcosa che non vedo...se qualcuno riesce a capire cosa c'è che non va mi fa un grandissimo favore.
Prova con 0.1L al posto di 0.1 e 100.0L al posto di 100.0 ;)
Quindi è tipo una perdita di precisione? Ma 100.0 non viene convertito a double automaticamente? Ora provo comunque, grazie.
Aggiornamento: ho messo la L dopo tutte le costanti numeriche coinvolte, anche quelle nel codice che chiama la funzione, purtroppo non è cambiato nulla, altri suggerimenti?
p.s. ma c'è qualche differenza fra il codice del main che ho messo e quello della funzione f? Non riesco a capire come mai si comportino diversamente.
Sinceramente non mi ricordo, ma mi sembra che s enon specifichi il formato venga usato float di default.
Se metti L, la costante è un long double a 80 bit.
100.0 viene convertito automaticamente a double, il problema però non dovrebbe essere 100, che ha una rappresentazione esatta anche su un float, ma 0.1 ;)
Si ma il fatto è che 0.1 non da problemi, infatti il secondo pezzo di codice funziona, quello che non funziona è la funzione f quando al posto di uno dei due parametri arriva 0.1 (che viene calcolato da un'altra parte direttamente come double).
Bisogna allora vedere come è stato calcolato...
Il valore che passo alla funzione* è 1.0L meno un double x che può valere 0.9, 0.8, 0.7, 0.6, 0.5 (in input si seleziona uno fra dei valori fissi). Il problema sorge quando è 0.9, dei valori sono sicuro perché ho messo un cout per ogni variabile per vedere cosa succede. Se faccio stampare i valori coinvolti in:
percentualeDiPartenzaInCentesimi = percentualeDiPartenza_*100.0L ottengo 10 e 0.1, se faccio stampare minimo = static_cast<int>(percentualeDiPartenzaInCentesimi); ottengo 9, se c'è di mezzo qualche conversione a float non so proprio dove sia, il tipo float non lo uso da nessuna parte e ho messo la L dopo tutte le costanti reali.
*È in una funzione che ha solo un return 1.0L - x come codice.
Stampa percentualeDiPartenzaInCentesimi ed avrai la tua risposta... Comunque è un problema di rappresentazione.
1 - 0.9 non fa 0.1 in floating point o meglio...non fa esattamente 0.1, ma magari 0.0999999, con il risultato che se fai il troncamento ottieni 9.
Stampa 10 come ho scritto prima, e se stampo minimo invece stampa 9, mi sembra assurdo ma è così. E la cosa più assurda è che nel programma che ho scritto nell seconda parte del primo post lo stesso calcolo dà 10.
Mi posti tutto il codice, anche quello che usi per passare i valori alla funziona ?
È un po' un casino mettere tutto, cmq ecco:
double percentualeMassima_ = 0.5L - getParteNonDisponibile();
/*dentro la funzione getParteNonDisponibile() c'è return 1.0L - x, con x che può valere 0.9-0.5*/
f(0.0L, percentualeMassima_);
/* la f è quella di prima, il codice non è esattamente così perché è il costruttore di un oggetto, è troppo lungo
metterlo tutto e il resto non c'entra con il calcolo, le variabili in f vengono modificate solo nel codice che ho messo.*/
ps grazie mille, se non si può fare così vedrò di trovare un altro modo, però non so proprio come trattare le percentuali se non come double.
Una cosa del genre quindi ?
#include <iostream>
using namespace std;
void f(double percentualeDiPartenza_, double percentualeMassima_) {
int minimo, massimo;
double percentualeDiPartenzaInCentesimi = percentualeDiPartenza_*100.0L, percentualeMassimaInCentesimi = percentualeMassima_*100.0;
minimo = static_cast<int>(percentualeDiPartenzaInCentesimi);
massimo = static_cast<int>(percentualeMassimaInCentesimi);
cout << minimo << " " << massimo << endl;
}
int main()
{
double percentualeMassima_ = 0.5L - 0.4L;
f(0.0L, percentualeMassima_);
return 0;
}
A me stampa 10...
anche a me se lo metto in un programma separato (vedi primo post, il secondo pezzo di codice), boh, può dipendere da qualche opzione del compilatore? Ho -Wl,-O1 -L/usr/lib -lQtGui -lQtCore -lpthread (è un'applicazione Qt).
Aggiornamento: dopo cambio la rappresentazione interna dei valori in modo da minimizzare sottrazioni e altro.
Credo che dipenda tutto da cosa ritorna getParteNonDisponibile();
ParteNonDisponibile ha solo una sottrazione dentro, fra la costante 1.0L e un campo dati double con valori fissi perchè li inserisco interi da uno spinBox e li converto in double...volendo potrei cambiare la rappresentazione di tutte le percentuali da double a int ma sarebbe una porcheria, anche perchè i calcoli li devo fare in double lo stesso.
Adesso ho leggermente cambiato il codice, al posto di parteNonDisponibile() uso getParteDisponibile():
double getParteDisponibile() const {
return 0.5L - quotaAcquistata;
}
In pratica ho spostato li dentro la sottrazione che facevo.
Succede sempre la stessa cosa però.
Cambia poco, quotaAcquistata come lo calcoli ?
Ho risolto, il problema (non so perché) era nella lettura del valore di quotaAcquistata come int dallo spinBox, ho usato un doubleSpinBox (non avevo visto che c'era anche quello) e funziona tutto, grazie mille per l'assistenza!
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.