Go Down

Topic: Mi servono 6-7 decimali ma float non va.... (Read 6866 times) previous topic - next topic

menniti

Il problema è noto, la cifra 2749999.9925 trattata con float diventa 2750000.0000, perché non riesce a gestire più di 7 cifre totali.
Nick Gammon qui ha risolto il problema con la sua lib; il link è proprio all'esempio che farebbe al caso mio, l'ho testato e funziona. Ora iniziano i miei guai, perché speravo di dover semplicemente aggiungere la lib ed uno-due comandi di attivazione e conversione al mio sketch per risolvere, invece mi trovo un casino di roba e non riesco a discernere cosa serve e cosa non mi serve.
La condizione del mio sketch è estremamente semplice: leggo un valore digitale e lo assegno alla variabile "valore", se uso una float ottengo risultati stravaganti, quindi sono costretto ad una unsigned long e "tagliare" i decimali. Se potessi recuperarli ne sarei felice, ho speranza di non dover usare tutti quei comandi, perché mi pare servano alla fine a generare quel cavolo di numero immenso, ma invece temo che quei comandi li dovrò usare al posto dei normali operatori aritmetici, ogni volta che eseguo un calcolo su tali numeri; in effetti ho necessità di fare un paio di divisioni ed un paio di moltiplicazioni per fattori numerici fissi (quindi non altre variabili), tutto qui :~
Qualcuno ha mai usato questa lib e può darmi un minimo di dritte, risparmiandomi un a settimana di studio, tempo che non ho e che non so nemmeno se mi basterà, viste le mie "conoscenze"?
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

nid69ita

#1
Jul 05, 2013, 08:27 pm Last Edit: Jul 05, 2013, 09:01 pm by nid69ita Reason: 1
Non l'ho mai usata, ma guardando gli esempi di @gammon, si direbbe che gestisce lui con dei puntatori a zone di memoria che allocherà dinamicamente questi numeri big.

primo dichiara quanti digit usare (e mi pare poteva usare byte invece di int), nel tuo caso 4 cifre decimali
Code: [Select]

#include "BigNumber.h"
static int DIGITS=4;


Poi dichiara le variabili di tipo bc_num e li inizializza a NULL, perciò presumo siano puntatori.
Code: [Select]

bc_num a=NULL, b = NULL, c = NULL;

Ma sembra che puoi anche dichiarate un bc_num x("123"); oppure bc_num y(123);   ma solo int in questo caso

Per inizializzare passa da stringa:
Code: [Select]
bc_str2num(&a, "42",DIGITS);
bc_str2num(&b, "18254546", DIGITS);

e per i calcoli usa solo sue funzioni che probabilmente sono le uniche che conoscono che struttura c'e' dietro a quei pointer.
Code: [Select]
bc_multiply(a,b,&c,DIGITS);
Nella libreria ultima versione vedo che ha anche creato l'overload per le operazioni più comuni tra due BignNumber, ovvero   c=a*b;   o altre operazioni +-*/%

Ha anche fatto overload dei confronti perciò puoi fare
if(a>=b)   dove
Una volta che le variabili big non gli servono più si ricorda di liberare la memoria:
Code: [Select]
bc_free_num (&b);a e b sono numeri big

bc_free_num (&c);



EDIT: nella ultima versione della libreria ha messo un pò di esempi (pde invece di ino e sono un pò diversi dagli esempi del link che hai postato). La libreria ora deriva da Printable e perciò puoi fare direttamente   Serial.printl(c);   dove c è un bignumber.
L'ha migliorata parecchio.
Code: [Select]

// BigNumber test: multiplication
#include "BigNumber.h"

void setup ()
{ Serial.begin (115200);
 Serial.println ();
 BigNumber::begin ();  // initialize library
 BigNumber::setScale (5);
 // test multiplication  
 BigNumber a = "564328376.33";
 BigNumber b = "18254546.22";
 BigNumber c = a + b;
 Serial.println (c);
}  // end of setup

void loop () { }


Se però usi cifre che assegni a dei bc, devono essere int, questo non mi funziona, sembra che b lo consideri troncandolo a int:
Code: [Select]

BigNumber a = "564328376";
BigNumber b =  111111111.22;
BigNumber c = a + b;

Qui se devi passargli un float:
http://forum.arduino.cc/index.php?topic=85692.msg1127105#msg1127105

E mi sembra importante leggere le note al fondo qui e la funzione "setScale" (impossibile fare un riassunto):
http://www.gammon.com.au/forum/?id=11519
my name is IGOR, not AIGOR

cyberhs

Ciao Michele.

Ho letto che la DUE gestisce variabili double "vere" a 8 byte e questa sarebbe la soluzione al tuo problema.

Vuoi vedere che tra un po' anche la UNO e la MEGA avranno le variabili di questo tipo?

leo72


Vuoi vedere che tra un po' anche la UNO e la MEGA avranno le variabili di questo tipo?

No, i float a 4 byte sono una limitazione dell'implementazione del compilatore gcc-avr per le mcu ad 8 bit.

cyberhs

Leo, conosci le motivazioni tecniche di una simile limitazione?

uwefed


Leo, conosci le motivazioni tecniche di una simile limitazione?

La potenza di calcolo dei controller a 8 Bit.
Ciao Uwe

menniti

karma Nid, nel doppio senso del termine XD XD
Mi pare che l'ultima parte del tuo intervento mi possa risolvere abbastanza rapidamente ogni problema, domattina mi metto a fare prove, quindi stay tuned perché certamente avrò bisogno...intando io visualizzo su LCD, ma vediamo una cosa per volta.
Un solo chiarimento: io ho scaricato la lib del link del primo post, tu parli di versioni diverse, è perché ti sei letto l'intero Topic (a proposito, un grosso grazie a Leo per la segnalazione :)) o ci sono link differenti? qual è quello più recente?
Grazie mille!
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

nid69ita

#7
Jul 05, 2013, 10:30 pm Last Edit: Jul 05, 2013, 10:41 pm by nid69ita Reason: 1
Io ho scaricato la libreria da link che tu hai messo. Poi sempre a quel link ho visto che gli esempi sono un pò diversi rispetto a quelli della libreria. Secondo me a quel link c'è poi il link al sito di @gammon che è sempre l'ultima versione.
Infatti nel link che hai postato a pagina 3 dice che ha migliorato la libreria rendendola "stampabile" con la print() e println()

La difficoltà della libreria secondo me è assegnare a questi numeri un valore.
Lo puoi fare o attraverso una stringa o solo da int, no da un float direttamente:
Code: [Select]
bc_num a=NULL,b=NULL;
a="12345.678";  // ok
b=32767;          // ok
b=111111111.2222;   // no, troncato a int


Nella setup() dovrai usare setScale(4)  visto che vuoi 4 decimali
Code: [Select]
BigNumber::begin ();  // initialize library  
BigNumber::setScale (4);


La libreria si appoggia ad una ulteriore libreria allegata che ha le primitive tipo un bc_str2num() e bc_int2num()
Non c'e' un bc_float2num() oppure bc_long2num() purtroppo
Si potrebbe chiedere a @Gammon se potrebbe inserirla.
my name is IGOR, not AIGOR

menniti

domattina mi metto a fare qualche piccola prova, e leggerò la tua prossima risposta, ora sto dormendo sulla tastiera :smiley-sleep: :smiley-sleep: :smiley-sleep: a questa domanda: nell'esempio che ho linkato lui alla fine ottiene un numero con un intero e 103 decimali, come ha fatto?

Inoltre ora a me viene il grandioso dubbio.... attualmente leggo un valore frutto di una serie di calcoli con timer e roba varia (una ulteriore lib, ovviamente), ma se il limite è dato dagli 8 bit, il mio valore iniziale 2.749.999,25 Hz REALE, applicato al micro, lo vedrò mai lato software? cioè se alla fine dei calcoli della prima lib io non riesco in alcun modo a preservare questo valore ed i suoi decimali, come faccio a ricostruire quello originale, da cui esso deriva?
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

nid69ita


domattina mi metto a fare qualche piccola prova, e leggerò la tua prossima risposta, ora sto dormendo sulla tastiera :smiley-sleep: :smiley-sleep: :smiley-sleep: a questa domanda: nell'esempio che ho linkato lui alla fine ottiene un numero con un intero e 103 decimali, come ha fatto?

Inoltre ora a me viene il grandioso dubbio.... attualmente leggo un valore frutto di una serie di calcoli con timer e roba varia (una ulteriore lib, ovviamente), ma se il limite è dato dagli 8 bit, il mio valore iniziale 2.749.999,25 Hz REALE, applicato al micro, lo vedrò mai lato software? cioè se alla fine dei calcoli della prima lib io non riesco in alcun modo a preservare questo valore ed i suoi decimali, come faccio a ricostruire quello originale, da cui esso deriva?

1. usa questa -> BigNumber::setScale (103);
mi sembra che la sua libreria internamente memorizza come stringa (vettore di char)

2. non credo riuscirai se non passi a fare i calcoli con la BigNumber
my name is IGOR, not AIGOR

lestofante

menniti, domanda stupida stupida.. se ti servono 6/7 cifre decimali, non puoi memorizzare i valori, anzichè come 10^0, come 10^-6?

puoi usare degli uint64_t per evere spazio a sufficienza (sono dei long long  :smiley-mr-green:), certo devi fare attenzione alla matematica.

la libreria di nick l'ho usata con successo recentemente ma ti ciuccia la RAM che è un piacere, se vuoi l'esempio funzionante (us anche l'add on di un altro tipo per seno coseno etcc) segui il link in firma, tra gli arduinoSketch cerca il "testGps" e trovi tutto

leggi qui la mia avventura:
http://forum.arduino.cc/index.php?topic=106614.msg799858#msg799858
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

cyberhs

#11
Jul 06, 2013, 06:06 am Last Edit: Jul 06, 2013, 06:09 am by cyberhs Reason: 1
Lesto, per favore, chiariscimi questo concetto.

Ho provato a dichiarare una variabile long long, ma l'IDE 1.0.5 non me la riconosce:

long long Prova = 12345678901;

error: integer constant is too large for 'long' type

Ma se faccio così il compilatore non da errore:
long long Prova = 12345678901ULL;

astrobeed


Ma se faccio così il compilatore non da errore:
long long Prova = 12345678901ULL;


Perché serve l'opzione "-mint8" ad avrgcc per poter utilizzare il long long int, purtroppo non è possibile fornirla tramite ide di Arduino, si può fare solo con AvrStudio, o direttamente da riga di comando, ovvero dall'ide di Arduino non è possibile utilizzare gli interi a 64 bit anche se supportati dalle avrlibc.
Scientia potentia est

leo72

Allora mi sa che dovete aggiornare la vostra toolchain.
Io con la toolchain Atmel compilo senza errori:

nid69ita

#14
Jul 06, 2013, 10:23 am Last Edit: Jul 06, 2013, 10:30 am by nid69ita Reason: 1
@leo però tu usi la 1.0.5+ (la nightly build). Magari è quella che cambia ?

EDIT: a me questo lo compila senza problemi con ide 1.0.5 e non ho cambiato la toolchain (ho però installato anche AvrStudio 6.1 ma non penso influenzi l'IDE !?!)
Code: [Select]

long long x=0;
void setup() {}

void loop()
{ x++;
}


Come detto da @cyberhs da problemi con una costante senza qualificatore, ma mi sembra corretto. Comunque i long long funzionano con il semplice 1.0.5 senza cambiare toolchain. C'e' solo quell'appunto sull'inizializzazione da costante.
my name is IGOR, not AIGOR

Go Up