zaokrouhlování

Wiring, C++, C, Java, ...
Pravidla fóra
Toto subfórum slouží k řešení obecných otázek kolem programování (konstrukce, knihovny, alokace paměti, ...)
Mau
Příspěvky: 18
Registrován: 11 zář 2020, 15:13
Reputation: 0

zaokrouhlování

Příspěvek od Mau » 19 dub 2021, 09:32

Prosím poradit toto

Kód: Vybrat vše

float a,b;


void setup() {
  Serial.begin(19200,SERIAL_8E1); //8E1 = Data bits 8, E/O Even/Odd parity, 1 stop bit
}

void loop() {
 delay(2000);
a=0.9;
b=0.9;
Serial.println(a==b);
Serial.println((String(a,1)).toFloat());
Serial.println((String(a,1)).toFloat()==b);
Serial.println((String(a,1)).toFloat()-b);
Serial.println("=================");
}

Výsledek:
1 // a
0.9 // (String(a,1)).toFloat())
0 // (String(a,1)).toFloat()==b)
0.00 // (String(a,1)).toFloat()-b) - pokus, že odečítá...
==========

Proč je vyhodnocení (String(a,1)).toFloat()==b) "0"?

Díky za pomoc.

Moje teorie je třeba, že toFloat() " The input String should start with a digit." - že by nula nebylo číslo. Ale pak "String doesn’t start with a digit, a zero is returned" - ale mě to nevrací nulu, vrací opravdu číslo 0.9.... ?

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

Re: zaokrouhlování

Příspěvek od ondraN » 19 dub 2021, 10:56

A když zkusíš tohle?

Kód: Vybrat vše

Serial.println(bool(String(a,1).toFloat()==b));
Nemám to teď na čem zkusit.
Taky nechápu, proč máš ty závorky u toho prvního objektu

Kód: Vybrat vše

  (String(a,1)).toFloat()
používá se to takhle

Kód: Vybrat vše

  String(a,1).toFloat()
tečka má stejnou precedenci jako závorka, takže je tam jen zbytečně matoucí

Mau
Příspěvky: 18
Registrován: 11 zář 2020, 15:13
Reputation: 0

Re: zaokrouhlování

Příspěvek od Mau » 19 dub 2021, 11:27

A když zkusíš tohle?

Kód: Vybrat vše

Serial.println(bool(String(a,1).toFloat()==b));

- nic, stejný výsledek - 0

....

používá se to takhle

Kód: Vybrat vše

  String(a,1).toFloat()
OK, díky, to je pravda.

Mau
Příspěvky: 18
Registrován: 11 zář 2020, 15:13
Reputation: 0

Re: zaokrouhlování

Příspěvek od Mau » 19 dub 2021, 11:30

Funguje toto, tedy odpoví "1":

Kód: Vybrat vše

Serial.println(String(a,1).toFloat()>==String("0.9").toFloat());
ale nefunguje toto, tedy odpoví "0":

Kód: Vybrat vše

Serial.println(String(a,1).toFloat()>==String(0.9).toFloat());

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

Re: zaokrouhlování

Příspěvek od ondraN » 19 dub 2021, 12:13

Máš tam nějaký bordel v operátorech. Co je to >==

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

Re: zaokrouhlování

Příspěvek od gilhad » 19 dub 2021, 12:52

Problem muze byt v zaokrouhlovani - 0.9 nema konecny binarni rozvoj a vysledek prekladace na PC a vysledek Arduina za chodu se muze drobne lisit (jak v delce rozvoje, tak v zaokrouhleni konce a v operacich okolo normalizaci)

Kód: Vybrat vše

0.9 /2 = 0, zb 0.9 (*2=1.8) =>0.
1.8 /2 = 0, zb 1.8 (*2=3.6) =>0.0
3.6 /2 = 1, zb 1.6 (*2=3.2) =>0.01

3.2 /2 = 1, zb 1.2 (*2=2.4) =>0.01 1
2.4 /2 = 1, zb 0.4 (*2=0.8) =>0.01 11
0.8 /2 = 0, zb 0.8 (*2=1.6) =>0.01 110
1.6 /2 = 0, zb 1.6 (*2=3.2) =>0.01 1100

3.2 /2 = 1, zb 1.2 (*2=2.4) =>0.01 1100 1 
2.4 /2 = 1, zb 0.4 (*2=0.8) =>0.01 1100 11
0.8 /2 = 0, zb 0.8 (*2=1.6) =>0.01 1100 110
1.6 /2 = 0, zb 1.6 (*2=3.2) =>0.01 1100 1100

...
Podobny problem jako zapsat v desitkove soustave 1/3 (zkus si na kalkulacce spocist 1/3 a vysledek (opsat a) vynasobit 3 - muze ti to vyjit taky 0.9999999, nebo to muze kalkulacka zaokrouhlit, nebo to muze ukazat zaokrouhlene a kdyz od toho pak odectes 0.999 a vynasobis 1000, tak se to najednou rozvine (a nejde rict, ze je to "spatne implementovane" proste mas omezenou presnost) - a zkus si to vypocist v ruce, kde to muzes zoptimalizovat na na 3/3*1 = 1 ) - proto se pri pocitani s float (ci s vyrazy, kde se float muze jako mezivysledek objevit) nedoporucuje bezmyslenkovite pouzivat "==", "<", "<=" ... , ale zvazit, zda neni potreba misto "a==b" pouzit radeji neco jako "( (a+0.1) > b ) && ( (a-0.1) < b )" (nebo misto 0.1 pouzit jinou hodnotu pro "prijatelnou chybu pri zaokrouholovani")

Rozvoj jde do nekonecna, kazda funkce se musi nekde zastavit, musi najit prvni 1 ve vypisu, podle ni upravit exponent a ulozit ten zbytek za ni a exponent jako binarni reprezentaci toho float, kdyz ho spocita prekladac (tedy float a) a ulozit si ho po konverzi na string a nasledne konverzi na float do jine promenne

Kód: Vybrat vše

float c=0;
c= (String(a,1)).toFloat()

// vypsat reprezentaci a
// vypsat reprezentaci c
// vypsat a==c

Mau
Příspěvky: 18
Registrován: 11 zář 2020, 15:13
Reputation: 0

Re: zaokrouhlování

Příspěvek od Mau » 19 dub 2021, 14:07

ondraN píše:
19 dub 2021, 12:13
Máš tam nějaký bordel v operátorech. Co je to >==
to jsem jen špatně přepsal, je tam " == " - omlouvám se za zmatení.

Mau
Příspěvky: 18
Registrován: 11 zář 2020, 15:13
Reputation: 0

Re: zaokrouhlování

Příspěvek od Mau » 19 dub 2021, 14:19

gilhad píše:
19 dub 2021, 12:52
Problem muze byt v zaokrouhlovani - 0.9 nema konecny binarni rozvoj a vysledek prekladace na PC a vysledek Arduina za chodu se muze drobne lisit...
To by mohlo být ono, už jsem se s tím setkal vlastně u matlabu....

Tak pokus:

a=0.9;
b=0.9;

Kód: Vybrat vše

Serial.println(String(a,1).toFloat()-b);
- vypíše 0

Kód: Vybrat vše

Serial.println((String(a,1).toFloat()-b)*1000000);
- vypíše 0.06

Tedy asi opravdu opravdu to nejsou stejná čísla, tedy "==" neplatí, protože se liší o 0,00000000prd

OK, tak díky.

Mau
Příspěvky: 18
Registrován: 11 zář 2020, 15:13
Reputation: 0

Re: zaokrouhlování

Příspěvek od Mau » 19 dub 2021, 14:30

gilhad píše:
19 dub 2021, 12:52

.... zkus si na kalkulacce spocist 1/3 a vysledek (opsat a) vynasobit 3 ....
Pokus na kalkulačce:

(1/3) *3 = 1

ale 1/3 = 0.333333333 a 0.333333333*3 = 0.999999999

Tedy je to jen o přesnosti čísel :)

Díky.

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

Re: zaokrouhlování

Příspěvek od ondraN » 19 dub 2021, 15:15

Asi metoda toFloat() používá jiný algoritmus převodu než matematická knihovna. Pak by ale mělo fungovat tohle.

Kód: Vybrat vše

Serial.println(String(a,1).toFloat() == String(b,1).toFloat());
Tam jsou obě čísla převedena stejným algoritmem, takže by měl být výsledek true.
Ale u floatů je radno používat pro porovnání >= nebo <= a pak nemůže dojít k podobným překvapením.

Odpovědět

Kdo je online

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