Problema del compilatore?

di il
8 risposte

Problema del compilatore?

Salve gente,
oggi purtroppo vi scrivo perché non riesco a risolvere questo problema, ovvero non riesco a capire perché quando vado a stampare sulla console il valore s mi appare un numero inferiore di 0.000001 rispetto al valore atteso; la variabile s è un multiplo di 0.04 quindi non mi capacito proprio di questi valori. Inoltre variando la variabile da me chiamata bug questo problema sparisce: es bug = 3.

0.040000
0.080000
0.120000
0.160000
0.200000
0.240000
0.280000
0.320000
0.360000
0.400000
0.440000
0.480000
0.520000
0.560000
0.600000
0.640000
0.680000
0.720000
0.760000
0.800000
0.840000
0.880000
0.920000
0.960000
1.000000
1.040000
1.080000
1.120000
1.160000
1.200000
1.240000
1.280000
1.320000
1.360000
1.400000
1.440000
1.480000
1.520000
1.560000
1.600000
1.640000
1.679999
1.719999
1.759999
1.799999
1.839999
1.879999
1.919999
1.959999
1.999999
2.039999
2.079999
2.119999
2.159999

Ho compilato dal prompt visual studio 2015 (cl file.c)
Ho estrapolato dal mio programma queste poche righe per semplificare e velocizzare la lettura chiaramente alcune operazioni appaiono strane.

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

float micros() {

	LARGE_INTEGER freq, val;
	QueryPerformanceFrequency(&freq);
	QueryPerformanceCounter(&val);
	return ((float)val.QuadPart / (float)freq.QuadPart);
}

int main() {

	/*variabili*/
	float Timecounter;
	float s = 0;
	float bug = 0.5;

	/*a*/
	Timecounter = micros();
	while (bug * 3 * (micros() - Timecounter) * (micros() - Timecounter) <= 4) {

		if (bug * (micros() - Timecounter) * (micros() - Timecounter) * (micros() - Timecounter) >= s + 0.04) {

			s = s + 0.04;
			printf("%f", s);
		}
	}

	getchar();
}

8 Risposte

  • Re: Problema del compilatore?

    Non usare float, ci sono degli arrotondamenti! usa degli interi (per gestire la virgola considera i valori moltiplicati opportunamente per una potenza di 10)
  • Re: Problema del compilatore?

    candaluar ha scritto:


    Non usare float, ci sono degli arrotondamenti! usa degli interi (per gestire la virgola considera i valori moltiplicati opportunamente per una potenza di 10)
    Non capisco come possa essere colpa dei float quello che viene stampato sulla console è il prodotto del seguente algoritmo n= n + 0.04, dove n inizialmente è uguale a 0, soltanto iterando questo algoritmo per un po' di volte compare l' errore ma la virgola non si sposta è sempre alla seconda cifra decimale. Tutto il resto che compone il programma serve solo a gestire il ciclo quindi il numero di interazioni. I float se non sbaglio sono precisi alla 6 cifra decimale ed è quello che mi serve essendo la portata della funzione micros in micro secondi. Se fosse colpa dei float come potrebbe funzionare questa funzione?

    float sqrt(float n) {

    int val;
    float radice;
    for (val = 1; val*val < n; val++) {}
    radice = val - 1;
    for (val = 0; val != 6; val++) {

    radice = radice - ((radice* radice - n) / (2 * radice));
    }
    return radice;
    }

    val != 6 con questo settaggio intendo proprio non sprecare tempo a calcolare cifre inutili. Se puoi aiutarmi a capire meglio mi saresti d' aiuto perché così ancora non mi è chiara la causa del problema.
  • Re: Problema del compilatore?

    C'e' un intero corso SEMESTRALE all'Universita' per SPIEGARE quello che non capisci.

    Il corso si chiama Calcolo Numerico

    Le rogne sono TANTE, MILIONI DI MILIONI, come la stella di Negroni

    Ma fondamentalmente il tutto si riconduce a:

    1) la rappresentazione dei numeri in floating point e' in BINARIO, e non in decimale, e certi numeri, in binario, NON SI POSSONO RAPPRESENTARE!

    2) quando fai delle operazioni, ci sono SEMPRE degli errori di arrotondamento che si ACCUMULANO.
    Esistono tecniche decisamente SOFISTICATE per LIMITARE (MAI OVVIARE/ELIMINARE) questo problema.

    3) MAI E POI MAI (IN ASSOLUTO) usare un float in confronti di tipo UGUAGLIANZA, DISUGUAGLIANZA, ma SEMPRE considerare la presenza di un EPSILON in cui il numero potrebbe variare.

    In pratica, il tuo numero in floating point lo DEVI SEMPRE CONSIDERARE come scritto nel seguente modo: (f,eps)
    dove 'eps' e' l'errore di rappresentazione che si porta SEMPRE dietro.
    Nei casi semplic, questo errore lo puoi trascurare, MA NON SEMPRE
    E COMUNQUE va SEMPRE CONSIDERATA la sua presenta, anche se non se ne fa nulla

    NON E' UN PROBLEMA DEL COMPILATORE. Caso mai e' un problema della CPU!!!
  • Re: Problema del compilatore?

    migliorabile ha scritto:


    C'e' un intero corso SEMESTRALE all'Universita' per SPIEGARE quello che non capisci.

    Il corso si chiama Calcolo Numerico

    Le rogne sono TANTE, MILIONI DI MILIONI, come la stella di Negroni

    Ma fondamentalmente il tutto si riconduce a:

    1) la rappresentazione dei numeri in floating point e' in BINARIO, e non in decimale, e certi numeri, in binario, NON SI POSSONO RAPPRESENTARE!

    2) quando fai delle operazioni, ci sono SEMPRE degli errori di arrotondamento che si ACCUMULANO.
    Esistono tecniche decisamente SOFISTICATE per LIMITARE (MAI OVVIARE/ELIMINARE) questo problema.

    3) MAI E POI MAI (INASSOLUTO) usare un float in confronti di tipo UGUAGLIANZA, DISUGUAGLIANZA, ma SEMPRE considerare la presenza di un EPSILON in cui il numero potrebbe variare
    Intanto grazie del tuo tempo poiché essere aiutati non mai dai darsi per dovuto;

    Mi spiace ma informatica non mi prende io vado a fisica, che poi li i pc non servano è un altra storia infatti eccomi qui... la sintassi dei vari linguaggi mi uccide, oggi ho perso due ore perché avevo dimenticato un / 6....

    Il punto 3, nel mio programma ho tenuto conto di errori dovuti a tempi di esecuzione per questo ci sono solo confronti per => e =< ma ora devo litigare con i float . Ogni variabile x bit può contenete 2^x seguendo il calcolo combinatorio perciò ci sarà una voce per il segno una po' per la posizione della virgola e tante per il numero, dimmi se sbaglio. Allora se il float è un 32bit mi pare bello spazioso, sono intenzionato a risolvere tale problema anche perché questa è un libreria necessaria ad un altro programma e deve funzionare, tenterei io di scrivere uno standard ma non saprei come spiegarlo alla macchina inoltre sono sicuro che sia già stato fatto e in modo più che eccellente. Ciò detto mi indicheresti gentilmente che cosa(Calcolo Numerico proprio tutto?) e se possibile dove studiarlo; poiché le dispense ci sono ma beccare quella giusta... altra storia

    Le rogne sono TANTE, MILIONI DI MILIONI, come la stella di Negroni Apprezzata

    Comunque +- 10^-6 è un errore accettabile dello stesso ordine di quelli derivati dai tempi di computazione
  • Re: Problema del compilatore?

    Mi sono fatto un poco di cultura, ho letto lo standard IEEE e intuito l' epsilon, ciò detto qual' è la soluzione migliore? Dichiaro tutto long int e moltiplico per 10^6 (come aveva suggerito candaluar) oppure, ribadisco che dell' epsilon ho giusto un intuizione dichiarando una variabile come double anziché float essendo double-precision binary floating-point l' errore sarà minore? Un' aiuto per la situazione pratica mi gioverebbe. Questa è solo curiosità per modificare lo standard devo lavorare in assebly o devo scendere ancora?
  • Re: Problema del compilatore?

    0) ma che acciderboline e' questo misterioso standard?

    1) fare fisica e non voler aver a che fare con l'informatica e' come il pasticciere che non vuole avere a che fare con lo zucchero perche' ingrassa: CAMBIA MESTIERE

    2) l'assembler NON CENTRA UNA PIPPA: se hai letto lo standard DEVI aver capito che NON E' un problema di linguaggio perche' alla fin fine, e' SEMPRE la CPU che esegue il programma, ed e' LEI che fa i conti, QUINDI anche in assembler LE ROGNE RIMANGONO

    3) passare a double NON ELIMINA il problema: e' sempre li e li ci rimane. L'unica cosa che cambia e' che l'errore non e' alla 6^ cifra ma alla 12^. QUINDI

    4) usare i longint NON RISOLVE il problema: stai passando da un numero in virgola mobile ad uno in virgola fissa. La cosa funziona con somma e sottrazione, diventa un problema con moltiplicazione, un incubo con divisione

    5) anche a fisica c'e' il corso di Calcolo Numerico. SEGUILO

    6) non so quale e' la bibbia del calcolo numerico. Esistono infiniti libri. Uno qualunque va bene

    7) se la banale sintassi di un linguaggio di programmazione ti uccide, la sintassi allucinante dei tensori, divergenze, gradienti, operazioni su indici, equazioni differenziali, integrali circolari/elittici/tripli avrebbe dovuto vaporizzarti, anzi, annichilirti, con la potenza di 70kg di materia che si scontra con altrettanta antimateria.

    Il sistema solare e' ancora qui', la terra pure, l'italia anche, e tu scrivi post, quindi il problema non e' poi cosi' grave
  • Re: Problema del compilatore?

    A me non è chiarissimo quale sia, esattamente, il risultato che vuoi ottenere.
    Se lo espliciti ti dico la soluzione ottima.
    ---
    Riguardo ai tuoi "turbamenti", la versione breve è:
    - per ragioni di velocità (cuttone) i numeri floating point vengono spesso (ma non sempre) impacchettati in una rappresentazione adatta per occupare 4 byte (singola precisione) oppure 8 (doppia)
    - storicamente esistevano dei coprocessori matematici in grado proprio di elaborare questi formati "impacchettati" in modo efficiente (o meglio, più efficiente rispetto alla CPU). Si tratta della serie x87. Ogni CPU Intel aveva il suo relativo coprocessore matematico (8086->8087, 80286->80287). In realtà esistevano anche coprocessori matematici non-Intel, ma è un'altra storia. A un certo punto il coprocessore matematico è stato "inglobato" dentro la CPU, e tutte le CPU odierne (Intel) sono dotate di questo silicio, che una volta era fisicamente separato (si comprava e pagava a parte)
    - i linguaggi "rozzi", tipo quello che stai usando, mappano in maniera pressochè diretta i tipi fondamentali con le strutture "rozze" della CPU.Ecco perchè i float C, non sorprendentemente, non sono altro che 4 byte "impacchettati"
    - questo metodo (l'impacchettamento) non può rappresentare numeri reali (questo è banale, R è denso), e neppure i razionali a dir la verità, perchè hanno una "granularità" (mi verrebbe da dire una sorta di h di Planck in versione informatica
    - la questione è ancora più complessa di così, ma compendiando avrai dei "buchi" nella rappresentazione dei float, questo può (in generale accade) introdurre degli errori di arrotondamento
    - i quali errori si possono sommare "amplificandosi" fino a diventare sensibili. Cuttone su come si minimizza questo problema, la stabilità numerica degli algoritmi eccetera. Tutta roba penso del primo massimo secondo anno
    - il problema esiste comunque anche usando "float grossi" (cioè da 16 byte, poco diffusi). c'è sempre e comunque.

    QUINDI?

    Quindi quando operi puoi adottare alcuni accorgimenti

    1) te li tieni, sapendo il perchè e il percome
    2) adotti ovunque possibile gli interi, "trasformati" alla bisogna in float
    3) usi librerie a precisione multipla (ce ne sono parecchie)
  • Re: Problema del compilatore?

    PS nota di servizio: il problema non è neppure della CPU, o meglio c'entra il sistema operativo.
    Il metodo per il quale viene eseguito il codice FFP in emulazione può variare, e capita - in casi eccezionali, ma a me personalmente è capitato - che il medesimo programma, eseguito su Vista, dia risultati diversi rispetto a tutti gli altri SO Microsoft.

    Ciò, che apparirebbe incredibile, è invece una conseguenza nell'utilizzo di funzioni "occulte", o addirittura nell'intercettazione di opcode FFP (i mitici x87) per l'utilizzo "en passant" di routine software.
Devi accedere o registrarti per scrivere nel forum
8 risposte