Konverze unsigned long to float a opačně

Odpovědět
Ludek
Příspěvky: 291
Registrován: 02 pro 2019, 08:14
Reputation: 0
Bydliště: České Budějovice

Konverze unsigned long to float a opačně

Příspěvek od Ludek » 13 lis 2023, 08:51

Ahoj všem,
tak jsem se konečně dostal k datum, co posílá elektroměr EM357. Dlouho jsem se trápil, než jsem zjistil, že data jsou typu float.
A tím jsem zjistil něco co nechápu...
Jak vlastně funguje převod unsigned long to float? Co se vlastně s čísly děje? A to samé i opačně.
Umí to někdo vysvětlit, jak to tam konverze dělá?
Našel jsem toto a je to SUPER, funguje ale stejně nechápu :

Kód: Vybrat vše

//
//  Test prevodu unsigned long to float a zpatky
//
union equiv { float x; unsigned long y; }
equiv ;
unsigned long DataA, DataB;
float vysledek;
//===========================================================
void setup() {
  Serial.begin(19200);
  DataA = 0x437040A5;             // = 240.25
  DataB = 0x3F800000;             // = 1.00
}
//===========================================================
void loop() {
//................ unsigned long to float ...................
equiv.y = DataA;     vysledek = equiv.x;
Serial.println(vysledek,6);
delay(1000);
equiv.y = DataB;     vysledek = equiv.x;
Serial.println(vysledek,6);
delay(1000);
//................ float to unsigned long ...................
float Num1 = 240.252517;
unsigned long UnLA = (*(unsigned long*)&Num1);
Serial.println(UnLA, HEX);
delay(1000);
float Num2 = 1.00;
unsigned long UnLB = (*(unsigned long*)&Num2);
Serial.println(UnLB, HEX);
delay(5000);

}

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Konverze unsigned long to float a opačně

Příspěvek od ondraN » 13 lis 2023, 09:38

Tady je docela slušně vysvětlená vnitřní reprezentace float čísel.
https://en.wikipedia.org/wiki/Floating-point_arithmetic

peterple
Příspěvky: 156
Registrován: 22 zář 2021, 20:20
Reputation: 0

Re: Konverze unsigned long to float a opačně

Příspěvek od peterple » 13 lis 2023, 17:02

Deje sa to že sa mení interný formát ako je reprezentované číslo. V oboch prípadoch je potreba aspoň poznať ten interný formát.
V oboch prípadoch je mohutnosť množiny 2^32 nakoľko aj long aj float používa na uloženie 4 byte. Lenže každý ten formát je určený na niečo iné a potom pri konverzii vznikajú zaujímavé vedľajšie efekty.
Prvý formát je pre celé čísla v rozsahu 0 až 4294967295. To nám dovoľuje zobraziť všetky 4 miliardy čísel s krokom po 1.
Druhý formát je pre reálne čísla v rozsahu ±1.175494351E-38 až ± 3.402823466E+38. Celý tento rozsah sa ale musí vtrepať opäť do celkového počtu 4miliardy kombinácií. Deje sa to tak že čísla majú obmedzený počet platných cifier. V toto prípade na 6-7. To znamená že ak skonvertuješ nejaký long čo je cez 10miliónov na float tak stratíš určitý počet platných miest. Čím väčšie číslo tým viac tratíš. Ak to potom skonvertuješ späť na long tak takmer zaručene dostaneš iné číslo ako si tam mal pred tým.

Toto nedokáže žiadny komputer vedieť (okrem javasriptu - tam je všetko double a hotovo), kde aké čísla sú vhodné a preto je to na programátorovi aby rozumel o čo ide a použil správne typy na správne účely.

Podobne ako strojár musí vedieť či použije hliník, alebo ocel. Oboje sa dá opožiť ako konštrukčný prvok, ale o použití rozhodujú detaily. A preto potrebuje strojár aj informatik 5 rokov štúdia na VŠ aby im rozumel.

Samotné vykonanie konverzie je už len technický detail toho ktorého jazyka. V C sú dva typy - implicitná a explicitná
Implicitná je že to kompilátor podľa nejakého vopred daného postupu určí sám akého typu bude výsledný výraz. Explicitná je taká že mu to nadiktuje programátor ako on uzná za vhodné. Teda kludne môže rozhodnúť že to čo je v premenej deklarovanej ako long je v skutočnosti float alebo opačne. A to je použité v tom tvojom programe, ktorému nerozumieš. A mi zase nerozumieme čomu nerozumieš, lebo ti nevidíme do hlavy.
Možno keď si prečítaš toto, tak porozumieš.
https://ccsuniversity.ac.in/bridge-libr ... ing%20.pdf

V tvojom programe sa na striedanie pohľadov používa datová konštrukcia s názvom union. Čo je zase na jednu menšiu prednášku z VŠ ak máš rozumieť detailom a nie len sa naučiť poučku.

Samotné algoritmy čo konverzie robia sú zase len technické detaily zapísane v tom ktorom programovacom jazyku a sú pre float pomerne komplikované. Takže každý sa spolieha na knižnice a tie sú zase napísane podľa nejakej normy (IEEE-754), aby to fungovalo rovnako na celom svete.

Uživatelský avatar
gilhad
Příspěvky: 789
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Konverze unsigned long to float a opačně

Příspěvek od gilhad » 14 lis 2023, 01:59

Perteple to vzal učeně a má pravdu.

Ale zjednodušeně na jde taky koukat takhle:
1 bit je buď nula, nebo jednička., nic víc, nic míň.
1 byte má 8 bitů, 4 byte má 32 bitů. zase nic víc, nic míň.

Co ty bity znamenají je určeno tím, jak se s níma zrovna pracuje.
Každý bit může být třeba nějaký příznak.
Nebo se vezme 8 bitů a pracuje se s tím jako s písmenem.
Nebo se vezme 8 bitů a pracuje se s tím jako s číslem.
Nebo se vezme 32 bitů a pracuje se s tím jako se 4 znaky.
Nebo se vezme 32 bitů a pracuje se s tím jako s unsigned long
Nebo se vezme 32 bitů a pracuje se s tím jako s float

Pořád to leží ve stejné paměti a pořád ty bity jsou jen nějaké nuly a jedničky.

Takže pokud se na jeden kus paměti díváš jako na float, tak ho tak klidně můžeš používat.
Ale taky se na stejný kus paměti m§žeš pro změnu dívat jako na unsigned int a používat ho tak.
Bity tam budou pořád ty stejné, ale ten význam bude jiný.

Struktura union dělá přesně tohle - má nějaké žásti, ale ty jsou v paměti na stejném místě a překrývají se.
Takže equiv.x je float, když tam dáš nějaké to číslo v plovoucí čárce, tak se na ty 4B=32bitů uloží. když si ho odtamtud vezmeš, tak dostaneš stejnou bitovou hodnotu, jako jsi tam dal (a stejné desetiné číslo).
A equiv.y je unsigned int, když tam dáš nějaké to celé číslo bez znamínka, tak se na ty 4B=32bitů uloží. když si ho odtamtud vezmeš, tak dostaneš stejnou bitovou hodnotu, jako jsi tam dal (a stejné celé číslo).

Ale když do equiv.x dáš nějaké číslo v plovoucí čárce, ale pak si vyzvedneš equiv.y, které je v paměti na tom samém místě, tak dostaneš stejnou bitovou hodnotu, jako jsi tam dal, ale ta odpovídá nějakému celému číslu bez znamínka, které na první pohled vůbec nepřipomíná to číslo v plovoucí čárce (jen má stejné bity).

A když naopak do equiv.y dáš nějaké celé číslo, ale pak si vyzvedneš equiv.x, které je v paměti na tom samém místě, tak dostaneš stejnou bitovou hodnotu, jako jsi tam dal, ale ta odpovídá nějakému číslo v plovoucí čárce, které na první pohled vůbec nepřipomíná to celé číslo (jen má stejné bity).

Takže takhle se dají mezi sebou převádět různě kódované typy, pokud jen chceš zachovat stejnou bitovou hodnotu, třeba kvůli snadným přenosům (přenášet celá čísla umí snadno každý a nezmění je) a pak si to zase převést zpátky (jako to dělá ten elektroměr).

(Samozřejmě pokud bys věděl, jaká data posílá a rovnou to přijímal jako číslo v plovoucí čárce, tak by to fungovalo taky - pořád jde o ty samé bity, čili nuly a jedničky)

Uživatelský avatar
kiRRow
Příspěvky: 1170
Registrován: 07 kvě 2019, 07:03
Reputation: 0
Bydliště: Opava

Re: Konverze unsigned long to float a opačně

Příspěvek od kiRRow » 14 lis 2023, 08:51

https://www.h-schmidt.net/FloatConverter/IEEE754.html - tady se i můžeš podívat jak to uvnitř toho floatu vypadá.

Ludek
Příspěvky: 291
Registrován: 02 pro 2019, 08:14
Reputation: 0
Bydliště: České Budějovice

Re: Konverze unsigned long to float a opačně

Příspěvek od Ludek » 16 lis 2023, 07:05

Lidi, vy jste borci !
Díky tak už jsem v obraze, to mě nenapadlo, že to je tak šílené...

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Konverze unsigned long to float a opačně

Příspěvek od ondraN » 16 lis 2023, 12:32

Není to žádná šílenost. Je to vysoce efektivní a optimální pro další operace ve floating point aritmetice.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 48 hostů