C++ Radice quadrata (cicli)

Pubblicità

MatteFra

Nuovo Utente
Messaggi
105
Reazioni
14
Punteggio
45
Ciao a tutti,
ho scritto un programmino che chiede all'utente di inserire un numero reale e, dopo averlo letto, chiede nuovamente di indovinare la radice quadrata di quel numero. Se l'utente indovina il programma mostra la stringa "Bravo!" altrimenti chiede all'utente se vuole riprovare. Il programma però non funziona non appena digito un valore con la virgola, infatti con varie prove (compreso il procedimento inverso con la potenza) il programma afferma che il valore non è la radice quadrata del numero cercato. Provando ad esempio il valore 25.3268614564 la cui radice quadrata vale 5.03258, il compilatore non fornisce la soluzione corretta.

Codice:
// enunciati di inclusione
#include<iostream>
#include<string>

// enunciato using namespace
using namespace std;

int main()
{
    // dichiarazioni di variabili
    double num;
    double res;
    int ans;
    
    // enunciati eseguibili
    cout << "Inserisci un valore intero: ";
    cin >> num;
    
    do
    {
        cout << "Determina la radice quadrata! ";
        cin >> res;
        
        if (num == res * res)
            cout << "Bravo!" << endl;
        else
        {
            cout << "Hai sbagliato. Vuoi riprovare?\n 1 - si\n 2 - no\n";
            cin >> ans;
        }
    } while (ans == 1);
    
    // enunciato return
    return 0;
}
 
Cio' dipende dalla "propagazione degli errori" dovuti agli arrotondamenti/troncamenti dei numeri in virgola mobile.
In pratica, la divisione prima e la moltiplicazione poi, con uno stesso numero, fornira' lo stesso risultato, a meno di un "EPSILON", in valore assoluto.
Questo diventa maggiormente significativo nel calcolo di una radice, in quanto concettualmente si tramuta nel limite (approssimazione) di una successione (o di un metodo altrernativo che comunque comprende piu' operazioni in virgola mobile)

Quindi dovresti usare qualcosa del genere:
C++:
        double quad = res * res;
        if (num <= quad+FLT_EPSILON && num >= quad-FLT_EPSILON ) {

FLT_EPSILON (cosi' come DBL_EPSILON) lo trovi in <cfloat>
 
Ultima modifica:
Cio' dipende dalla "propagazione degli errori" dovuti agli arrotondamenti/troncamenti dei numeri in virgola mobile.
In pratica, la divisione prima e la moltiplicazione poi, con uno stesso numero, fornira' lo stesso risultato, a meno di un "EPSILON", in valore assoluto.
Questo diventa maggiormente significativo nel calcolo di una radice, in quanto concettualmente si tramuta nel limite (approssimazione) di una successione (o di un metodo altrernativo che comunque comprende piu' operazioni in virgola mobile)

Quindi dovresti usare qualcosa del genere:
C++:
        double quad = res * res;
        if (num <= quad+FLT_EPSILON && num >= quad-FLT_EPSILON ) {

FLT_EPSILON (cosi' come DBL_EPSILON) lo trovi in <cfloat>
Grazie mille, non ci sarei arrivato :)
 
Cio' dipende dalla "propagazione degli errori" dovuti agli arrotondamenti/troncamenti dei numeri in virgola mobile.
In pratica, la divisione prima e la moltiplicazione poi, con uno stesso numero, fornira' lo stesso risultato, a meno di un "EPSILON", in valore assoluto.
Questo diventa maggiormente significativo nel calcolo di una radice, in quanto concettualmente si tramuta nel limite (approssimazione) di una successione (o di un metodo altrernativo che comunque comprende piu' operazioni in virgola mobile)

Quindi dovresti usare qualcosa del genere:
C++:
        double quad = res * res;
        if (num <= quad+FLT_EPSILON && num >= quad-FLT_EPSILON ) {

FLT_EPSILON (cosi' come DBL_EPSILON) lo trovi in <cfloat>
Ho provato ma non mi funziona come dovrebbe mi da sempre errato
 
Ho provato ma non mi funziona come dovrebbe mi da sempre errato
Prova a vedere se e' (anche!) un problema di troncamento input:
lo stream di input dovrebbe avere un numero di cifre significative preimpostate, dopo la virgola, di 6... lo controlli con cout << cin.precision();

Fai prima pero' questa (importante) verifica sul numero in se':
Invece di passare il valore (attraverso cin), assegna il valore direttamente alla variabile (nel codice, bypassando l'input).

Se il numero in se' funzionasse... prova ad aumentare le cifre significative dell'input. utilizzando:
cin.precision(X);

con X che identifica il numero di cifre significative che desideri impostare per il canale di input.
Questa impostazione deve essere fatta prima dell'acquisizione della variabile (ossia prima dell'utilizzo di cin)

Edit:
Questo codice, con i valori da te citati (il valore 25.3268614564 la cui radice quadrata vale 5.03258), e compilati su gcc (GCC) 13.0.1 20230401 (Red Hat 13.0.1-0), funziona:

C++:
// enunciati di inclusione
#include<iostream>
#include<string>
#include <cfloat>

// enunciato using namespace
using namespace std;

int main()
{
    // dichiarazioni di variabili
    double num;
    double res;
    int ans;

// precisione input a 12 cifre, dopo la virgola
    cin.precision(12);
    cout <<  "cin prec: " << cin.precision() << " - cout prec: " << cout.precision() << endl;
 
    // enunciati eseguibili
    cout << "Inserisci un valore intero: ";
    cin >> num;
 
    do
    {
        cout << "Determina la radice quadrata! ";
        cin >> res;

        double quad = res * res;
        if (num <= quad+FLT_EPSILON && num >= quad-FLT_EPSILON ) }
            cout << "Bravo!" << endl;
            ans = 2; // aggiunta postuma, altrimenti non esce dal do-while (e.g. se si sbaglia il primo valore, e poi si digita "1")
        }
        else
        {
            cout << "Hai sbagliato. Vuoi riprovare?\n 1 - si\n 2 - no\n";
            cin >> ans;
        }
    } while (ans == 1);
 
    // enunciato return
    return 0;
}

... e produce questo OUTPUT:

*** Ad onor del vero,su GCC v13.0, funziona anche SENZA dover aumentare la precisione di input con cin.precision(X);: vedi la precisione attuale nella prima riga: cin prec: 6 - cout prec: 6
(per questo motivo e' importante verificare che il numero in se' funzioni, bypassando temporaneamente l'input)

Quindi ti chiedo: che compilatore stai usando (sigla completa, compresa la versione) e che valori stai immettendo?

Sarebbe anche importante verificare se si ha qualche flag attivo (di default o meno) che privilegi la velocita' delle operazioni in virgola mobile a discapito della precisione (e che ha impatto sorattutto su funzioni trascendenti, logaritmiche ed esponenziali... ergo anche radici quadrate):
e.g. per MS compiler:
/fp:fast
Cito dal link sopra: "A causa di questa ottimizzazione avanzata, il risultato di alcuni calcoli a virgola mobile può differire da quelli prodotti da altre opzioni /fp: "
/fp:precise
/fp:strict


Come puoi vedere ho provato (anche) diversi input per determinare quanto fosse "affidabile" l'approssimazione:
Screenshot at 2023-04-27 14-07-40.png

P.S. Se desideri anche un outupt con maggiore precisione, e quindi con troncamento meno significativo, devi utilizzare analogamente cout.precision(X);, oppure dai un'occhiata a std::setprecision(X);
 
Ultima modifica:
Prova a vedere se e' (anche!) un problema di troncamento input:
lo stream di input dovrebbe avere un numero di cifre significative preimpostate, dopo la virgola, di 6... lo controlli con cout << cin.precision();

Fai prima pero' questa (importante) verifica sul numero in se':
Invece di passare il valore (attraverso cin), assegna il valore direttamente alla variabile (nel codice, bypassando l'input).

Se il numero in se' funzionasse... prova ad aumentare le cifre significative dell'input. utilizzando:
cin.precision(X);

con X che identifica il numero di cifre significative che desideri impostare per il canale di input.
Questa impostazione deve essere fatta prima dell'acquisizione della variabile (ossia prima dell'utilizzo di cin)

Edit:
Questo codice, con i valori da te citati (il valore 25.3268614564 la cui radice quadrata vale 5.03258), e compilati su gcc (GCC) 13.0.1 20230401 (Red Hat 13.0.1-0), funziona:

C++:
// enunciati di inclusione
#include<iostream>
#include<string>
#include <cfloat>

// enunciato using namespace
using namespace std;

int main()
{
    // dichiarazioni di variabili
    double num;
    double res;
    int ans;

// precisione input a 12 cifre, dopo la virgola
    cin.precision(12);
    cout <<  "cin prec: " << cin.precision() << " - cout prec: " << cout.precision() << endl;
 
    // enunciati eseguibili
    cout << "Inserisci un valore intero: ";
    cin >> num;
 
    do
    {
        cout << "Determina la radice quadrata! ";
        cin >> res;

        double quad = res * res;
        if (num <= quad+FLT_EPSILON && num >= quad-FLT_EPSILON ) }
            cout << "Bravo!" << endl;
            ans = 2; // aggiunta postuma, altrimenti non esce dal do-while (e.g. se si sbaglia il primo valore, e poi si digita "1")
        }
        else
        {
            cout << "Hai sbagliato. Vuoi riprovare?\n 1 - si\n 2 - no\n";
            cin >> ans;
        }
    } while (ans == 1);
 
    // enunciato return
    return 0;
}

... e produce questo OUTPUT:

*** Ad onor del vero,su GCC v13.0, funziona anche SENZA dover aumentare la precisione di input con cin.precision(X);: vedi la precisione attuale nella prima riga: cin prec: 6 - cout prec: 6
(per questo motivo e' importante verificare che il numero in se' funzioni, bypassando temporaneamente l'input)

Quindi ti chiedo: che compilatore stai usando (sigla completa, compresa la versione) e che valori stai immettendo?

Sarebbe anche importante verificare se si ha qualche flag attivo (di default o meno) che privilegi la velocita' delle operazioni in virgola mobile a discapito della precisione (e che ha impatto sorattutto su funzioni trascendenti, logaritmiche ed esponenziali... ergo anche radici quadrate):
e.g. per MS compiler:
/fp:fast
Cito dal link sopra: "A causa di questa ottimizzazione avanzata, il risultato di alcuni calcoli a virgola mobile può differire da quelli prodotti da altre opzioni /fp: "
/fp:precise
/fp:strict


Come puoi vedere ho provato (anche) diversi input per determinare quanto fosse "affidabile" l'approssimazione:
Visualizza allegato 458429

P.S. Se desideri anche un outupt con maggiore precisione, e quindi con troncamento meno significativo, devi utilizzare analogamente cout.precision(X);, oppure dai un'occhiata a std::setprecision(X);
Chiaro ora sì torna.. Grazie mille!
 
Ultima modifica:
Pubblicità
Pubblicità
Indietro
Top