Ansicht:   

#156568

Mr. Teflon

12.08.2009, 01:06:11

C - seltsamer Rundungseffekt ??? (pc.coding)

Hallo,

ich zeige Euch mal den Code vom Berechnungsteil für negative Temperaturen.
Ich begrenze die Ausgabe/Anzeige auf -99,9°C. Mit der Abfrage

if(wert2 > 9.99)
wert2 = 9.99;

Die Zahl wird nur noch in Einzelteile zerlegt, sodass eigentlich im Terminal -99.9 ankommen/angezeigt werden müßten.

ABER! Ich bekomme -99,8 angezeigt !!!

Wie kann denn plötzlich aus einer 9 eine 8 werden?

Spinne ich oder wer spinnt?  :???:

Gibts Erklärungen?



// ********** KTY10-6 Temperaturberechnung aus A/D und Ausgabe an COM ************ \\\\
// *** Berechnung mit den kalibrierten SensorDigits nur gültig mit Rv 5,6kOhm  *** \\\\
// ********** -30°C ... 0°C zweistellig und 0°C ... 150°C dreistellig ************ \\\\

   
void com_Temperatur (uchar chan)
   {
   SensorMin = 186;				// A/D Digitwert 186 = Temperatursensor -30°C
   SensorNull = 231;				// A/D Digitwert 231 = Temperatursensor   0°C
   Sensor100 = 386;				// A/D Digitwert 386 = Temperatursensor 100°C
   SensorMax = 443;				// A/D Digitwert 443 = Temperatursensor 150°C
   	                     
   wert2 = (float) ad_in(chan);			// A/D Wandler auslesen und als float wert2 übergeben
     
   if(wert2 < 231)				// wenn Temperatur negativ, dann hier rechnen
   {
   
   com_txd (\'-\');				// Zeichen \"-\" Ausgabe an COM
      				                // Bsp. wert2 = 201   
   wert2 = (wert2-SensorNull)/(Sensor100-SensorNull)* -10; // Temperaturberechnung, wert2 = 1,935
   
   if(wert2 > 9.99)				// wenn Temperatur kälter wie -99°C, dann 
      wert2 = 9.99;				// wird Anzeige auf -99,9°C gesetzt
	  
   D = wert2;								
   com_txd (D + 48);				// Zehner Stelle als Ganzzahl an COM
   
   wert2 = wert2 - D;						
   wert2 = wert2 * 10;						
   D = wert2;								
   com_txd (D + 48);				// Einer Stelle als Ganzzahl an COM
   
   com_txd (0x2e);				// Dezimalpunktausgabe an COM
	
   wert2 = wert2 - D;						
   wert2 = wert2 * 10;						
   D = wert2;								
   com_txd (D + 48);				// erste Kommastelle als Ganzzahl an COM
      
   // com_txd (176);				// Zeichen ° an COM
   com_txd (\'C\');
   
   com_print(\"\\n\\r\");               		// Zeilenende
   }
   

--
___________
Tschau
Mr. Teflon

#156573

MudGuard zur Homepage von MudGuard

München,
12.08.2009, 07:48:39

@ Mr. Teflon

C - seltsamer Rundungseffekt ???

> Ich begrenze die Ausgabe/Anzeige auf -99,9°C. Mit der Abfrage
>
> if(wert2 > 9.99)
> wert2 = 9.99;

Das finde ich schon mal verwirrend - wieso 9.99, wenn es -99.9 sein sollen?

> Die Zahl wird nur noch in Einzelteile zerlegt, sodass eigentlich im
> Terminal -99.9 ankommen/angezeigt werden müßten.
> ABER! Ich bekomme -99,8 angezeigt !!!

> // ********** -30°C ... 0°C zweistellig und 0°C ... 150°C dreistellig

Außerdem ist -99.9 außerhalb dieses Bereichs ...

> wert2 = (float) ad_in(chan); // A/D Wandler auslesen und als float

> if(wert2 < 231) // wenn Temperatur negativ, dann hier rechnen

231 ist doch nicht negativ. Sehr seltsam ...

> if(wert2 > 9.99) // wenn Temperatur kälter wie -99°C, dann
> wert2 = 9.99; // wird Anzeige auf -99,9°C gesetzt

> D = wert2;
> com_txd (D + 48); // Zehner Stelle als Ganzzahl an COM
>
> wert2 = wert2 - D;
> wert2 = wert2 * 10;
> D = wert2;
> com_txd (D + 48); // Einer Stelle als Ganzzahl an COM
>
> com_txd (0x2e); // Dezimalpunktausgabe an COM

Bei der ganzen Rechnerei können jedesmal Rundungsfehler geschehen - beachte dabei insbesondere, daß nicht jede Dezimalzahl im zugrundeliegenden Binärformat exakt darstellbar ist. So wie z.B. 1/7 im Dezimalsystem eine nicht-endliche Darstellung hat ( 0,142857 142857 142857 142857 142857 usw.), gibt es Zahlen, die im Binärsystem eine nicht-endliche Darstellung haben - da der Speicherplatz für die Zahl aber endlich ist, wird dann gerundet).

> wert2 = wert2 - D;
> wert2 = wert2 * 10;
> D = wert2;
> com_txd (D + 48); // erste Kommastelle als Ganzzahl an COM

>
> // com_txd (176); // Zeichen ° an COM
> com_txd (\'C\');

Steht sprintf oder printf zur Verfügung? Damit kannst Du die Fließkommazahl in einen String umwandeln, ohne den Wert dabei durch mehrfache Berechnungen zu verändern.

--
[image]
MudGuard
O-o-ostern

#156615

Mr. Teflon

12.08.2009, 14:04:47

@ MudGuard

C - seltsamer Rundungseffekt ???

> > Ich begrenze die Ausgabe/Anzeige auf -99,9°C. Mit der Abfrage
> >
> > if(wert2 > 9.99)
> > wert2 = 9.99;
>
> Das finde ich schon mal verwirrend - wieso 9.99, wenn es -99.9 sein
> sollen?

Damit wird gleichzeitig die Kommastelle angepaßt. Sonst müßte man nochmal extra durch 10 rechnen.

> > Die Zahl wird nur noch in Einzelteile zerlegt, sodass eigentlich im
> > Terminal -99.9 ankommen/angezeigt werden müßten.
> > ABER! Ich bekomme -99,8 angezeigt !!!
>
> > // ********** -30°C ... 0°C zweistellig und 0°C ... 150°C dreistellig
>
> Außerdem ist -99.9 außerhalb dieses Bereichs ...

Das tut nichts zur Sache. Ist nur mein Kommentar für später. Ich kann auch mit 3,00 statt 9,99 auf -30°C optisch begrenzen.

>
> > wert2 = (float) ad_in(chan); // A/D Wandler auslesen und als float
>
> > if(wert2 < 231) // wenn Temperatur negativ, dann hier rechnen
>
> 231 ist doch nicht negativ. Sehr seltsam ...

Ist nicht seltsam. Ist korrekt. Du lernst mir C und ich Dir Elektronik.  ;-)
Die Zahl 231 ist der Digitwert vom A/D Wandler. Er arbeitet mit 10 Bit Auflösung. Der Dualwert 2^10 ist ja 1024 dezimal. Dadurch gibt mir der A/D Wandler einen Wertebereich zwischen 0 ... 1023 zurück, was an seinem zu messenden Eingang 0 ... 5V entspricht. Durch die äußere Beschaltung des Sensors, dessen Meßbereich und Kennlinie, liegt der Nullpunkt vom Sensor bei 1,1x Volt und diese entsprechen 231 Digit vom A/D Wandler. Wenn der Nullpunkt bei 0 Digit liegen würde, könnte ich nie Temp. unter 0°C messen. Der Software Nullpunkt etc. muß eh immer an den Sensor angepaßt werden durch ausmessen. Alles klar?

>
> > if(wert2 > 9.99) // wenn Temperatur kälter wie -99°C, dann
> > wert2 = 9.99; // wird Anzeige auf -99,9°C gesetzt
>
> > D = wert2;
> > com_txd (D + 48); // Zehner Stelle als Ganzzahl an COM
> >
> > wert2 = wert2 - D;
> > wert2 = wert2 * 10;
> > D = wert2;
> > com_txd (D + 48); // Einer Stelle als Ganzzahl an COM
> >
> > com_txd (0x2e); // Dezimalpunktausgabe an COM
>
> Bei der ganzen Rechnerei können jedesmal Rundungsfehler geschehen -
> beachte dabei insbesondere, daß nicht jede Dezimalzahl im zugrundeliegenden
> Binärformat exakt darstellbar ist. So wie z.B. 1/7 im Dezimalsystem eine
> nicht-endliche Darstellung hat ( 0,142857 142857 142857 142857 142857
> usw.), gibt es Zahlen, die im Binärsystem eine nicht-endliche Darstellung
> haben - da der Speicherplatz für die Zahl aber endlich ist, wird dann
> gerundet).

Hierbei wird nicht gerundet. Die auszugebende Zahl wird nur durch eine Art Software Schieberegister zerlegt und immer die erste linke Stelle wird ausgegeben. Es darf auch nur immer einstellig sein links vorm Komma.

>
> > wert2 = wert2 - D;
> > wert2 = wert2 * 10;
> > D = wert2;
> > com_txd (D + 48); // erste Kommastelle als Ganzzahl an COM
>
> >
> > // com_txd (176); // Zeichen ° an COM
> > com_txd (\'C\');
>
> Steht sprintf oder printf zur Verfügung? Damit kannst Du die
> Fließkommazahl in einen String umwandeln, ohne den Wert dabei durch
> mehrfache Berechnungen zu verändern.

Was ist sprintf oder printf?
Fertige Befehle in C oder meinst Du vorhandene Funktionen in Bsp. Codes die ich zur Verfügung habe.
Das muß aber dann auch mit der LCD Ausgabe funktionieren. Das Terminal ist ein Zwischenschritt bis mein LCD funktioniert.

--
___________
Tschau
Mr. Teflon

#156631

MudGuard zur Homepage von MudGuard

München,
12.08.2009, 17:45:35

@ Mr. Teflon

C - seltsamer Rundungseffekt ???

> > Bei der ganzen Rechnerei können jedesmal Rundungsfehler geschehen -
> > beachte dabei insbesondere, daß nicht jede Dezimalzahl im
> zugrundeliegenden
> > Binärformat exakt darstellbar ist. So wie z.B. 1/7 im Dezimalsystem
> eine
> > nicht-endliche Darstellung hat ( 0,142857 142857 142857 142857 142857
> > usw.), gibt es Zahlen, die im Binärsystem eine nicht-endliche
> Darstellung
> > haben - da der Speicherplatz für die Zahl aber endlich ist, wird dann
> > gerundet).
>
> Hierbei wird nicht gerundet.

doch. Bei jedem Rechenschritt wird gerundet. Intern. Ohne daß Du es merkst oder beeinflussen kannst. Weil das Rechenergebnis wieder in die (begrenzte) interne Darstellung gebracht werden muß.

> > Steht sprintf oder printf zur Verfügung? Damit kannst Du die
> > Fließkommazahl in einen String umwandeln, ohne den Wert dabei durch
> > mehrfache Berechnungen zu verändern.
>
> Was ist sprintf oder printf?

Etwas Eigeninitiative wäre angebracht. Google steht auch Dir zur Verfügung.

--
[image]
MudGuard
O-o-ostern

#156655

Mr. Teflon

12.08.2009, 21:27:06

@ MudGuard

C - seltsamer Rundungseffekt ???

Hallo,

> > Hierbei wird nicht gerundet.
>
> doch. Bei jedem Rechenschritt wird gerundet. Intern. Ohne daß Du es merkst
> oder beeinflussen kannst. Weil das Rechenergebnis wieder in die (begrenzte)
> interne Darstellung gebracht werden muß.

Okay, verstanden. Danke.


> > > Steht sprintf oder printf zur Verfügung? Damit kannst Du die
> > > Fließkommazahl in einen String umwandeln, ohne den Wert dabei durch
> > > mehrfache Berechnungen zu verändern.
> >
> > Was ist sprintf oder printf?
>
> Etwas Eigeninitiative wäre angebracht. Google steht auch Dir zur
> Verfügung.

Bist Du Dir sicher ...  :lol2:

--
___________
Tschau
Mr. Teflon

#158060

Mr. Teflon

23.08.2009, 22:26:18

@ MudGuard

C - seltsamer Rundungseffekt ???

Hallo,

also sprintf und printf kennt die Entwicklungsumgebung nicht.
Dann muß ich die herkömmliche Art laut den Bsp. nehmen.
Danke Euch erstmal.

--
___________
Tschau
Mr. Teflon

#156643

LEO_68

12.08.2009, 20:21:23

@ Mr. Teflon

C - seltsamer Rundungseffekt ???

Hi,

mal ne Frage vorweg. Welchen Compiler verwendest Du. Bei den meisten kannst Du nämlich im Debugmode die Werte anzeigen lassen. Ein paar Breakpoints und dann durchgesteppt und schon passts.

Was ich aber nicht verstehe ist folgendes



> 
> if(wert2 > 9.99)				// wenn Temperatur kälter wie -99°C, dann 
> wert2 = 9.99;				// wird Anzeige auf -99,9°C gesetzt
> 
> D = wert2;	


hier wird D zu 9.99

					
> com_txd (D + 48);				// Zehner Stelle als Ganzzahl an COM
> 
> wert2 = wert2 - D;						


hier weist Du wert2 die Subtraktion von wert2 und D zu also: wert2=9.99-9.99. Soll das so sein oder fehlt noch was in dem Code. Mal davon abgesehn dass keine deklaration für D vorhanden ist?

Ansonsten wie MudGuard geschrieben hat mal ne printf oder sprintf versuchen.

Gruß LEO

Gruß LEO

#156658

Mr. Teflon

12.08.2009, 21:40:44

@ LEO_68

C - seltsamer Rundungseffekt ???

> Hi,
>
> mal ne Frage vorweg. Welchen Compiler verwendest Du. Bei den meisten
> kannst Du nämlich im Debugmode die Werte anzeigen lassen. Ein paar
> Breakpoints und dann durchgesteppt und schon passts.
>
> Was ich aber nicht verstehe ist folgendes
>


> 
> >
> >    if(wert2 > 9.99)				// wenn Temperatur kälter wie -99°C, dann 
> >      wert2 = 9.99;				// wird Anzeige auf -99,9°C gesetzt
> > 	  
> >    D = wert2;	
> 


> hier wird D zu 9.99
>
>

					
> >    com_txd (D + 48);				// Zehner Stelle als Ganzzahl an COM
> >    
> >    wert2 = wert2 - D;						
> 


> hier weist Du wert2 die Subtraktion von wert2 und D zu also:
> wert2=9.99-9.99. Soll das so sein oder fehlt noch was in dem Code. Mal
> davon abgesehn dass keine deklaration für D vorhanden ist?
>
> Ansonsten wie MudGuard geschrieben hat mal ne printf oder sprintf
> versuchen.
>
> Gruß LEO
>
> Gruß LEO

Hallo,

unsigned char D;

wert2 ist 9,99

D = wert2; >>> D wird wegen Ganzzahl 9, nicht 9,99

Also die 1. Stelle vorm Komma. Darum muß \"wert2\" bei der ganzen \"Zahlenweiterschubserei\" vorm Komma einstellig bleiben, sonst klappt das nicht.

Dieses \"Schieberegister\" ist nicht von mir, ich habe es jedoch verstanden wie funktioniert. Das verstehen ist mir erstmal wichtig. Geht bestimmt auch einfacher. Es gibt da noch so eine Funktion \"ltoa_format\", die verstehe ich aber bis jetzt nicht.

Ich werde mich wegen printf und sprintf schlau machen.


//*************************************   Long in Zeichenkette umwandeln  
int ltoa_format(char *erg, long zahl, uint vk, uint nk,  char vorz )
{ // Out-String, Eingabe, Vorkommastellen, Nachkommastellen, Vorzeichen \'+\' oder \' \' 
   long temp;
   int  i;
   i = vk + nk + 1;                    // Stringlaenge  
   erg[i--] = 0;                       // Zeichenketten-Ende  
   if ( zahl == 0 ) erg[i--] = \'0\';    // Spezialfall 0  
   else 
   {
      if ( zahl < 0 )
      {
      vorz  = \'-\';                     // negatives Vorzeichen  
      zahl *=  -1;                     // mit positiver Zahl weiterrechnen 
      }
      while( i >= 0 && 
	       ( zahl > 0 || i+2*( nk != 0 ) > vk) ) // in vk ist vorz enthalten  
      {
      if (i==vk&&nk!=0) erg[i--]=\'.\';  // Dezimalpunkt, wenn nk abgearbeitet  
      else 
      {
      temp     =  zahl / 10;           // ganzzahlige Division  
      erg[i--] = (zahl - temp*10) + 48; // Digit abtrennen und ASCII Zeichen ablegen */
      zahl     =  temp;                // fuer naechsten Durchlauf um 1 Digit verkuerzt */
      }
   }
   if ( i >= 0 ) erg[i--] = vorz;      // Vorzeichen schreiben  
   }
   while( i >= 0 ) erg[i--] = \' \';     // Anfang mit Leerzeichen fuellen  
   return  vk + nk + 1;                // Stringlaenge zurueckgeben  
}

--
___________
Tschau
Mr. Teflon

Ansicht:   
Auf unserer Web-Seite werden Cookies eingesetzt, um diverse Funktionalitäten zu gewährleisten. Hier erfährst du alles zum Datenschutz