C++ Radice quadrata (cicli)

MatteFra

Nuovo Utente
96
12
CPU
i7-8750H 2.2GHz
HDD
Local C Disk: 512 gb; Local D Disk: 1 tb
RAM
16 gb
GPU
GTX 1050 TI 4 gb
OS
Windows 10 home
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;
}
 

BrutPitt

Utente Attivo
1,166
1,262
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:

MatteFra

Nuovo Utente
96
12
CPU
i7-8750H 2.2GHz
HDD
Local C Disk: 512 gb; Local D Disk: 1 tb
RAM
16 gb
GPU
GTX 1050 TI 4 gb
OS
Windows 10 home
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 :)
 
  • Mi piace
Reazioni: BrutPitt

BAT

Moderatore
Staff Forum
Utente Èlite
22,948
11,581
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
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
facciamo che il numero sia intero...
 
  • Mi piace
Reazioni: bigendian

MatteFra

Nuovo Utente
96
12
CPU
i7-8750H 2.2GHz
HDD
Local C Disk: 512 gb; Local D Disk: 1 tb
RAM
16 gb
GPU
GTX 1050 TI 4 gb
OS
Windows 10 home
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
 

BrutPitt

Utente Attivo
1,166
1,262
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:
  • Mi piace
Reazioni: MatteFra

MatteFra

Nuovo Utente
96
12
CPU
i7-8750H 2.2GHz
HDD
Local C Disk: 512 gb; Local D Disk: 1 tb
RAM
16 gb
GPU
GTX 1050 TI 4 gb
OS
Windows 10 home
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:

Ci sono discussioni simili a riguardo, dai un'occhiata!

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili