Ciao a tutti. Vi scrivo per chiedervi dei chiarimenti in merito all'aritmetica con Arduino.
Ho scritto uno Sketch che converte le coordinate equatoriali di un corpo celeste in coordinate altazimutali e viceversa.
Dovendo lavorare con i numeri reali utilizzo delle variabili float.
Una riga del codice è la seguente:
ho notato che i calcoli eseguiti nell’ordine sopra riportato comportano delle perdite di cifre significative, con conseguente imprecisione nella conversione.
Riadattando l’ordine degli operatori come sotto indicato
delta_target = (DECtarget * pigreco) / 648000;
ovvero dividendo per 3600*180 = 648000 solo dopo aver effettuato tutte le moltiplicazioni, l’incertezza dovuta alla perdita di cifre significative si riduce drasticamente, tanto da essere sufficiente ai miei scopi.
Questo fatto dovrebbe dipendere da come vengono gestiti i dati nelle float, ma non mi è del tutto chiaro.
Qualcuno potrebbe darmi delle spiegazioni in merito?
Grazie e buon pomeriggio a tutti
>zioetzi: essendo il tuo primo post, nel rispetto del regolamento (… punto 13, primo capoverso), ti chiedo cortesemente di presentartiQUI (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO ... Grazie.
Guglielmo
P.S.: Qui una serie di link utili, NON necessariamente inerenti alla tua domanda: - serie di schede by xxxPighi per i collegamenti elettronici vari: ABC - Arduino Basic Connections - pinout delle varie schede by xxxPighi: Pinout - link generali utili: Link Utili
Non so dirti cosa è accaduto dal 2013 ad oggi (... manutenzione forum ? Mah) ... comunque, nell'apposito thread una tua presentazione non c'è e quindi ... dedica 5 minuti a farla :), così ci racconti bene quali conoscenze hai di elettronica e di programmazione e ci aiuti a "calibrare" le risposte
zioetzi:
ho notato che i calcoli eseguiti nell’ordine sopra riportato comportano delle perdite di cifre significative, con conseguente imprecisione nella conversione.
Se è quello che sospetto (cioè che parte dei calcoli venga fatta con numeri interi) così si dovrebbe risolvere:
zioetzi:
Questo fatto dovrebbe dipendere da come vengono gestiti i dati nelle float, ma non mi è del tutto chiaro.
I float sono valori rappresentati tramite un esponenziale, in pratica hai una mantissa moltiplicata per una potenza di due, il problema è che con 32 bit rimangono solo 24 bit per la mantissa, 1 è usato per il segno e 7 per l'esponente, pertanto questo porta ad un grosso limite nelle cifre significative disponibili, tipicamente tra 6 e 7.
Per dirla in modo semplice se con un float vuoi rappresentare 123.123454678 in realtà questo diventa 123.1234 nella migliore delle ipotesi, tutte le altre cifre vnno perse, anzi è altamente probabile che diventa una cosa del tipo 123.1233999, come valore equivalente, perché si tratta comunque di una potenza. Qui trovi un'ottima spiegazione su come sono rappresentati i float in formato IEEE 754, è lo standard usato da tutti i compilatori C, anzi da quasi tutti compilatori anche per altri linguaggi.
Dato che sulle MCU a 8 bit al massimo i compilatori supportano i float, 32 bit, i double, 64 bit, anche se riconosciuti vengono comunque trattati come float, è sempre una cosa intelligente evitare di usarli se non strettamente necessario, p.e. nel caso dei calcoli trigonometrici dove sono obbligatori, e lavorare il più possibile con gli interi, se servono i decimali basta premoltiplicare tutti i valori per 10-100-1000, etc.
Rammento che il compilatore per gli AVR supporta gli interi a 64 bit, pertanto è possibile rappresentare valori molto grandi anche con la premoltiplicazione per emulare i decimali.
Fare calcoli solo con gli interi ha anche il vantaggio che richiede notevolmente meno tempo cpu rispetto ai calcoli con i float.
astrobeed:
Rammento che il compilatore per gli AVR supporta gli interi a 64 bit, pertanto è possibile rappresentare valori molto grandi anche con la premoltiplicazione per emulare i decimali.
Si gli int64_t e uint64_t sono i long long, confermo che sono supportati al 100% perché li uso nel codice per il sensore di pressione del rov, dove è presente un ADC delta sigma da 24 bit e i vari calcoli matematici per la conversione da valore raw a pressione reale vanno fatti forzatamente a 64 bit se si vuole ottenere la risoluzione reale a 18 bit.
Grazie, mi è tutto più chiaro.
Le float infatti le uso solo dove è strettamente necessario. Intervengono solo nella conversione tra le coordinate equatoriali/altazimutali e viceversa perché ci sono funzioni goniometriche, poi lavoro con le long.
Ciao e tutti,
Ezio
Ho un messo 123.52 in un long long quindi 12352
Poi ho messo 9.56 in un long long quindi 956
Moltiplicazione: 12352 * 956 => 11808512 123.52 * 9.56 => 1180.8512
Dopo la moltiplicazione tra i due long long se mi interessano solo 2 cifre decimali, devo ammazzare 2 cifre ?
Mi sono un pò perso.
nid69ita:
Dopo la moltiplicazione tra i due long long se mi interessano solo 2 cifre decimali, devo ammazzare 2 cifre ?
Beh si, 100A * 100B = 10000AB
Quindi il risultato va diviso per 100
Ci sono anche altri modi usando le potenze di due... che poi è sempre lo stesso
((10A)<<14) * ((10B)<<14) = 100268435456AB
e poi scorri tutto a destra di 28 bit:
(ab) >> 28
Nella mia idea per ogni oggetto Decimal decidi anche quanti decimali (max 10) e quindi potrei moltiplicare 2 Decimal con numero decimali desiderati diversi.
Forse è meglio scegliere un numero di decimali fisso, esempio 10 con una bella #define e quindi decidere quanti decimali stampare solo in fase di "output" del dato ?
Comunque mi sono impantanato con la operator*