Typumwandlung via Typecast?

#2949494
Lesenswert?

Hallo liebe Gemeinde,

mit einem ATMega16 möchte ich Ziffern einer uint32_t Variable auf einer 
6 Stelligen 7Segmentanzeige ausgeben. Die entsprechenden Ziffern picke 
ich mir mit einer geschriebenen Modulo-Funktion heraus. Folgendes 
Problem beschäftigt mich derzeit:

Ich berechne eine momentane Verbrauchsleistung mit Divison und 
Multiplikation, sodass mir wie zu erwarten die Nachkommastellen des 
Ergebnises verloren gehen. Ich benötige jedoch 3 der Nachkommastellen 
für weitere Funktionen in der selben Variable. Nun würde ich gerne meine 
unsigned long Variable so gestalten, dass die ersten drei Bits den 
Nachkommastellen entsprechen und die weiteren Bits eben der linken Seite 
der Fließkommazahl entsprechen. Da der Wertebereich von einer double 
bzw. float Variable meinem Ergebnis nicht genügt, fehlt mir der Ansatz 
um dieses Problem zu lösen.

Ich bin relativ neu in der Materie und habe etwas über Typecast gelesen, 
welches entsprechende Variablen als bestimmten Variablentyp behandelt. 
Könnte mir diese Möglichkeit die Nachkommastellen in meine uint32_t 
Variable einbinden oder bewege ich mich mit dieser Lösungsmögichkeit auf 
dem Holzweg?

Für effektivere bzw. sinnvollere Lösungsansätze / -vorschläge würde ich 
mich sehr freuen.

Danke im Voraus.
Gast #2949502
Lesenswert?

Mr. Xton schrieb:
> Da der Wertebereich von einer double bzw. float Variable meinem Ergebnis
> nicht genügt, fehlt mir der Ansatz um dieses Problem zu lösen.

Das mußt du jetzt mal näher erklären. Der Wertebereich von float ist 
RIESIG und um da rauszukommen, muss man schon einiges anstellen.

Was spricht dagegen, deine Zahlen als Milli-Irgendwas in der Integer 
Variablen abzulegen. Dann hast du die Tausendstel mit drin.
Gast #2949527
Lesenswert?

1. Typecast==Holzweg

2. Auszugebender Wertebereich ist unklar.
   6 Stellen wäre 0..999999, es sei denn, das Komma ist verschiebbar.
   Welchen Wertebereich willst Du ausgeben (z.B. 1mW..1000W) ?

3. Zweiter Absatz ist völlig unklar (3 Nachkommastellen ./. 3 Bits?!?)

4. "Da der Wertebereich von einer double bzw. float Variable
   meinem Ergebnis nicht genügt," - Glaube ich erstmal nicht,
   meinst Du was anderes?
#2949537
Lesenswert?

Danke euch beiden für die schnelle Antwort.

Hier ein Teilcode fürs Verständnis:


uint32_t wert = 0;

wert = 1 / IMPULSE_PRO_KWH;    // Umrechnung der Impulse in kWH
wert = wert * 1000;      // Umrechnung kWH in WH
wert = wert / 3600;            // Umrechnung WH in Ws
wert = wert / 100;            // Umrechnung Ws in Wms
wert = wert / Gemessene_Zeit_ms;  // Umrechnung mit verstrichener 
Zeit(ms)
wert = wert * 100;      // Rückrechnung Wms in Ws


Da ich die zeit wegen der Genauigkeit in ms ermittel, bin ich gezwungen 
kurzzeitig die Leistung in W/ms umzurechnen. Bereits in der 1. Rechnung 
gehen mir die Nachkommastellen verloren, sodass das Ergibnis an der 
Stelle Null ist. Würde ich hier mit float rechnen, bringt dieses jedoch 
den Nachteil mit sich, das mir die Vorkommastellen verloren gehen (wenn 
auch nich in der 1. Rechnung).

Also ist mein Ansatz, das ich die 1. Zeile in eine floatvariable 
schieben möchte.

Sprich:

float kwh_impuls = 1 / IMPULSE_PRO_KWH;

Jetzt benötige ich aber eine Rechnung aus uint32_t und float:

wert = (unsinged long) kwh_impuls * 1000;
...

Leider ist die Hardware noch nicht einsatzbereit und ich weiß nicht was 
die Variable wert dann beinhalten würde, da ich noch nie mit typecast 
gearbeitet habe.

lg
Gast #2949555
Lesenswert?

1
wert = 1 / IMPULSE_PRO_KWH;
2
wert = wert * 1000;
3
wert = wert / 3600;
4
wert = wert / 100;
5
wert = wert / Gemessene_Zeit_ms;
6
wert = wert * 100;

Wenn man das mal zusammenfasst, ergibt das:
1
wert = 1 / IMPULSE_PRO_KWH * 1000 / 3600 / 100 / Gemessene_Zeit_ms * 100;

Jetzt stellen wir alle Divisionen ans Ende:
1
wert = 1000 * 100 / 3600 / 100 / IMPULSE_PRO_KWH / Gemessene_Zeit_ms;

Äquivalent:
1
wert = 10 / (36 * IMPULSE_PRO_KWH * Gemessene_Zeit_ms);

So, das klappt natürlich nicht, weil da nur ganzzahlige Werte zwischen 0 
und 10 rauskommen können. Also hängst Du ein paar Nullen an:
1
wert = 10UL * 1000 * 1000 / (36 * IMPULSE_PRO_KWH * Gemessene_Zeit_ms);

Jetzt kann ein Wert zwischen 0 und 10 Millionen rauskommen. Da musst Du 
nur noch gedanklich bzw. bei der Ausgabe ein Komma an die richtige 
Stelle reinsetzen und Du bist fertig.

Mit float gehts natürlich auch, ist aber auf einem Mikrocontroller viel 
langsamer und hier unnötig.
#2949562
Lesenswert?

Danke euch!

@Hmm:

die Zeilen sind ausführlich aufgeführt um das Verständnis zu 
veranschaulichen. Werde es mir in einer Formel zu gemüte führen.



Zum Thema Vorkommastelle: Der Wertebereich von float kann Daten bergen, 
die sowohl im negativen, als auch im positiven Bereich sein können. Und 
im Vergleich zum unsigned long Typ kann dieser im positiven Bereich eine 
kleinere Zahl ablegen. Da weder die Zeit noch die Leistungsgröße pro 
Impuls bekannt ist, kann auch keine feste Aussage über die Größe der 
Momentanleistung getroffen werden. Sie soll im Endeffekt vielseitig 
einsetzbar sein.
Gast #2949566
Lesenswert?

> Werde es mir in einer Formel zu gemüte führen.

Mache es jetzt . Nicht später.

>Da weder die Zeit noch die Leistungsgröße pro
>Impuls bekannt ist, kann auch keine feste Aussage über die Größe der
>Momentanleistung getroffen werden.

Genau darüber aber musst Du Dir klar werden und Aussagen machen. Erst 
dann kannst Du Entwurfsentscheidungen treffen.
#2949584
Lesenswert?

Hmm schrieb:
> Vor allem reden wir hier über 10 hoch 14 Yottawatt. Hast Du die ganze
> Galaxie an Deinem Stromzähler? :-)


Das ist eben das Problem, ich kann zum jetzigen Zeitpunkt wirklich keine 
Aussage darüber treffen wieviel MW momentan verbraucht werden ;)

Spaß bei Seite, es handelt sich um ein Projekt für einen Abnehmer XY, 
und ich wollte es eben diesen so recht wie möglich machen, indem ich die 
Wertebereiche ziemlich groß gestalte. Man befindet sich einfach auf der 
sicheren Seite. Änderungen kann man im Praxiseinsatz immernoch bei 
Bedarf vornehmen. Und steht der Code einmal kann er auch bei anderen 
Abnehmern eingesetzt werden.

Vielen Dank nochmal, für eure Bemühungen.

lg
Gast #2949591
Lesenswert?

Standardmäßig sind Konstanten Integer-Werte, die auf dem AVR nur 16 Bit 
breit sind. Wenn man jetzt rechnet:
1
10 * 1000 * 1000
Dann passt das Ergebnis nicht in einen 16-Bit-Integer und es kommen 
seltsame Werte bei raus.

Also muss man mit 32 Bit rechnen. Das UL steht für unsigned long:
1
10UL * 1000 * 1000
Ebenso geht:
1
(uint32_t) 10 * 1000 * 1000

Damit stimmt dann der Wert wie erwartet. Für 64 Bit muss man ULL bzw. 
uint64_t nehmen.

Außerdem sollte man möglichst zuerst alle Konstanten zuerst miteinander 
verrrechnen, dann macht der Compiler das schon beim Optimieren. Im 
Maschinencode ist dann im Endeffekt nur noch eine 32-Bit-Division:
1
wert = (10UL * 1000 * 1000 / (36 * IMPULSE_PRO_KWH)) / Gemessene_Zeit_ms;

Oder für noch größeren Wertebereich, aber immer noch 32-Bit-Division:
1
wert = (uint32_t) (10ULL * 1000 * 1000 * 1000 / (36 * IMPULSE_PRO_KWH)) / Gemessene_Zeit_ms;
Gast #2949596
Lesenswert?

OK. Megawatt. Das wären dann 10 Hoch 32 Megawattsekunden. Der ganze 
Weltenergiebedarf betrug 2010 etwa 140.168 Mrd.kWh. Also so über den 
Daumen das 1/10^24 stel des Zahlenbereichs von (üblichen) Floats.

Dein Kunde muss seeeeeeeeeeeeeeeeeeeeeeeeeeeehr gross sein.

Ich möchte nochmal betonen wie wichtig es ist, sich vor einer 
Implementierung über die Grössenordnungen klar zu werden. An sich gehört 
sowas in das Lastenheft. Es dem Kunden so recht wie möglich zu machen 
ist ohnehin vergebliche Liebesmüh, da endlos.
#2949603
Lesenswert?

xfr schrieb:
> Standardmäßig sind Konstanten Integer-Werte, die auf dem AVR nur 16 Bit
> breit sind. Wenn man jetzt rechnet:
>
1
10 * 1000 * 1000
> Dann passt das Ergebnis nicht in einen 16-Bit-Integer und es kommen
> seltsame Werte bei raus.
>
> Also muss man mit 32 Bit rechnen. Das UL steht für unsigned long:
>
1
10UL * 1000 * 1000
> Ebenso geht:
>
1
(uint32_t) 10 * 1000 * 1000
>
> Damit stimmt dann der Wert wie erwartet. Für 64 Bit muss man ULL bzw.
> uint64_t nehmen.

Super, vielen Dank für die ausführliche Erklärung!
#2949612
Lesenswert?

Hmm schrieb:
> OK. Megawatt. Das wären dann 10 Hoch 32 Megawattsekunden. Der ganze
> Weltenergiebedarf betrug 2010 etwa 140.168 Mrd.kWh. Also so über den
> Daumen das 1/10^24 stel des Zahlenbereichs von (üblichen) Floats.
>
> Dein Kunde muss seeeeeeeeeeeeeeeeeeeeeeeeeeeehr gross sein.
>
> Ich möchte nochmal betonen wie wichtig es ist, sich vor einer
> Implementierung über die Grössenordnungen klar zu werden. An sich gehört
> sowas in das Lastenheft. Es dem Kunden so recht wie möglich zu machen
> ist ohnehin vergebliche Liebesmüh, da endlos.


Du hast natürlich vollkomen Recht mit dem was du schreibst.
Ich muss mich entschuldigen, da ich einige andere Funktionen des 
weiteren Programmcodes vorenthalten habe, wie zbsp. die Ermittlung der 
verbrauchten Leistung, die nach Jahren einen XY Betrag haben kann. Mein 
Programm soll für "jedermann" verwendbar sein, wodurch dieses letztlich 
von der Anzahl der Digits als auch der Impulse pro kwh abhängt. So sind 
bspw. die genannte Modulofunktion so geschrieben worden, dass eine Zahl 
(uint32_t) übergeben wird und somit für Verbrauchte- und 
Momentanleistung fungiert. Neben der genannten Funktion gibt es noch 
viele weitere, die ebenso zur Verfügung stehen. Im Gesamt handelt es 
sich um ein hobbymäßiges Projekt um meinen Lernerfolg im Umgang mit 
µCern und der Programmiersprache zu fördern.
Gast #2949739
Lesenswert?

Mr. Xton schrieb:
> Ich muss mich entschuldigen, da ich einige andere Funktionen des
> weiteren Programmcodes vorenthalten habe, wie zbsp. die Ermittlung der
> verbrauchten Leistung, die nach Jahren einen XY Betrag haben kann.

Die Leistung ist durch den Anschlußwert des Gebäudes nach oben begrenzt 
und von der Zeit unabhängig.
Falls du die Energie meinst, wird dir hauptsächlich die Auflösung Sorgen 
machen, da sich über die Zeit einerseits ein hoher Wert
aufsummieren kann und andererseits bei bei jedem Impuls nur ein geringer 
Betrag dazukommt. Float-Zahlen sind da eher kontraproduktiv, weil die 
Auflösung vom bereits aufsummierten Wert abhängt und außerdem noch Bits 
für den Exponenten verloren gehen.
Gast #2949758
Lesenswert?

Mr. Xton schrieb:
> Mein Programm soll für "jedermann" verwendbar sein, wodurch dieses
> letztlich von der Anzahl der Digits als auch der Impulse pro kwh abhängt.

Trotzdem muss dich der Wert IMPULSE_PRO_KWH nur wenig kümmern. Zur 
Messung der Gesamtenergie reicht es, die Impulse zu zählen und später 
für die Anzeige in absolute Einheiten umzurechnen. Dann gibt es keine 
Probleme mit der Auflösung und du hast einen Ganzzahl-Zähler, der 
optimal an den Impulsgeber angepaßt ist und trotzdem nichts verschenkt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren