Forum: Mikrocontroller und Digitale Elektronik Int to float riesiger Speicherbereich


von simso (Gast)


Lesenswert?

Hallo zusammen,

Ich habe folgendes "konstrukt" Programmiert leider benötigen die 
Codezeilen knapp 40% meines kompletten Code-speichers von meinem Atmega 
8....
Ziel ist es die nachkommastellen "abzuschneiden"
Kann man dies auch Speicherplatz schonender programmieren?
1
float a; 
2
float b;
3
float c;
4
5
uint8_t e;
6
7
c= a/b;
8
9
c=c+0,5;
10
11
e = (uint8_t)c;

Danke schonmal im Voraus

von Peter D. (peda)


Lesenswert?

Müssen a,b unbedingt float sein?

Für float braucht man den Compilerschalter -lm

von Josef D. (jogedua)


Lesenswert?

Und das
> c=c+0,5;
macht NICHT das, was es soll.

von Fabian O. (xfr)


Lesenswert?

Man kann es auf jeden Fall wesentlich kürzer hinschreiben:
1
float a; 
2
float b;
3
uint8_t e = a / b + 0.5;

Höchstwahrscheinlich wäre es aber sinnvoller, wenn Du statt Fließkomma- 
mit Festkommazahlen rechnen würdest. Hier ist ein Artikel, wie das geht:
http://www.mikrocontroller.net/articles/Festkommaarithmetik

von Ralph (Gast)


Lesenswert?


von C-Programmierer (Gast)


Lesenswert?

simso schrieb:
> Ich habe folgendes "konstrukt" Programmiert leider benötigen die
> Codezeilen knapp 40% meines kompletten Code-speichers von meinem Atmega
> 8....

Den Speicher benötigt nicht diese eine Code-Zeile, sondern die Tatsache, 
dass du Float-Zahlen verwendest und der Linker die dafür benötigten 
Bibliothek mit einbindet.
Wozu brauchst du auf einem µC Float?

Fabian O. schrieb:
> Man kann es auf jeden Fall wesentlich kürzer hinschreiben:

Und du meinst, das sich dadurch der Umfang des erzeugten Codes 
nennenswert ändert?

von simso (Gast)


Lesenswert?

Vielen Dank erstmal für die Infos,


Den Artikel mit der Festkommaarithmetik hatte ich bereits gelesen...

Ich habe mich auch nochmal schlau gemacht und dabei die Funktion 
dtostrf() gefunden. Werde Morgen mal meinen Code auf double Umbauen und 
dann nochmals Versuchen. Habe heute keine Lust mehr ;-)

Viele Grüße

von Walter S. (avatar)


Lesenswert?

simso schrieb:
> Werde Morgen mal meinen Code auf double Umbauen und
> dann nochmals Versuchen.

so wird das nicht besser,
Festkomma heißt das Zauberwort

von int (Gast)


Lesenswert?

simso schrieb:

> Den Artikel mit der Festkommaarithmetik hatte ich bereits gelesen...

Ok, und weiter? Du sollst ihn nicht des Lesens wegen lesen, sondern weil 
er dein Problem lösen kann. Wenn du ihn schon ignorierst, dann schreib 
wenigstens warum. Aber deiner Frage nach bist du nicht kompetent genug, 
um solche Vorschläge einfach im Vorbeigehen wegzuwischen.

> Ich habe mich auch nochmal schlau gemacht und dabei die Funktion
> dtostrf() gefunden. Werde Morgen mal meinen Code auf double Umbauen und
> dann nochmals Versuchen. Habe heute keine Lust mehr ;-)

Super! Du möchtest den Speicherverbrauch reduzieren, also nimmst du 
einfach den nächstgrößeren Datentyp. Das funktioniert sicher...

von C-Programmierer (Gast)


Lesenswert?

simso schrieb:
> Werde Morgen mal meinen Code auf double Umbauen und
> dann nochmals Versuchen.

Den Unterschied zwischen Double- und Float-Variablen kennst du?

von J.-u. G. (juwe)


Lesenswert?

C-Programmierer schrieb:
> simso schrieb:
>> Werde Morgen mal meinen Code auf double Umbauen und
>> dann nochmals Versuchen.
>
> Den Unterschied zwischen Double- und Float-Variablen kennst du?

Nun mal bitte langsam. Das kommt erst übermorgen dran.

von Fabian O. (xfr)


Lesenswert?

C-Programmierer schrieb:
> Und du meinst, das sich dadurch der Umfang des erzeugten Codes
> nennenswert ändert?

Der ist identisch (wenn man mit Optimierung compiliert). Wozu also fünf 
Zeilen schreiben, wenn es in einer viel übersichtlicher ist?

von foo (Gast)


Lesenswert?

simso schrieb:
> c=c+0,5;
Diese Zeile ist ein Bug. Sie ist äquivalent zu c+0;c =5;.

Auf einem 8 Bit uC werden 32 Bit IEEE754 Floats immer riesigen lahmen 
Code brauchen. Sollest du wirklich 32 Bit Floats brauchen dann nimm nen 
32 Bit uC mit Hardware FPU. Ansonsten schreibe deinen Code um.

von holger (Gast)


Lesenswert?

>leider benötigen die
>Codezeilen knapp 40% meines kompletten Code-speichers von meinem Atmega

Ja, und? Für unbenutzten Codespeicher bekommst du kein Geld zurück;)

von User (Gast)


Lesenswert?

Schreib mal die Wertebereiche von a und b.

von W.S. (Gast)


Lesenswert?

simso schrieb:
> leider benötigen die
> Codezeilen knapp 40% meines kompletten Code-speichers von meinem Atmega

Ja sagt mal ihr alle zusammen, wie winzig ist denn der Codespeicher 
dieses Atmegas oder andersherum: wie elefantös ist denn die 
Gleitkommalib bei diesen uC? Ist vielleicht immer automatisch die ganze 
sprintf(...) Lib mit dabei?

Ansonsten sind Bemerkungen wie
foo schrieb:
> Sollest du wirklich 32 Bit Floats brauchen dann nimm nen
> 32 Bit uC mit Hardware FPU. Ansonsten schreibe deinen Code um.

nicht wirklich hilfreich. Auch auf einem 8 Bitter braucht man 
Gleitkomma, wenn man es mit Meßwerten und deren Kalibrierung zu tun hat. 
Simples Beispiel: Reziprokzähler, wo der Quotient aus 2 größeren 
Zählständen (long) gebildet werden muß und man auch Nachkommastellen auf 
dem Display sehen will.

W.S.

von Michael (Gast)


Lesenswert?

W.S. schrieb:
> Simples Beispiel: Reziprokzähler, wo der Quotient aus 2 größeren
> Zählständen (long) gebildet werden muß und man auch Nachkommastellen auf
> dem Display sehen will.

Was hat Float jetzt mit Nachkommastellen zu tun?
Float hat verglichen mit einer gleich großen Fixkommazahl eine 
verringerte Genauigkeit, weil etliche Bits für den Exponenten verbraucht 
werden. Dafür ist der Dynamikbereich größer, was aber für viele 
Anwendungen, die sich in einem festen Zahlenbereich abspielen, überhaupt 
keine Rolle spielt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

simso schrieb:

> Ich habe folgendes "konstrukt" Programmiert leider benötigen die
> Codezeilen knapp 40% meines kompletten Code-speichers von meinem Atmega
> 8....

Das "Konstrukt" enthält float +, / und Konvertierung nach int.

Meine Erfahrung mit float ist, daß es weniger Platz verbraucht als die 
von dir genannten ca. 3kB.

Projekt 4000 Stellen von Pi mit ATtiny2313 passt zum Beispiel in 
einen ATtiny2313 und verwendet folgende float-Routinen:

+, -, *, /, lrintf, floorf,  Konvertierung von int nach float.

Zudem enthalten die 2kB Code ausser float-Arithmetik noch andere Sachen 
wie UART-Ausgabe und Integer-Arithmetik modulo n, nämlich Multiplikation 
mod n und Exponentiation mod n.

von (prx) A. K. (prx)


Lesenswert?

Zumindest früher wars doch so, dass avr-gcc die falschen recht 
monströsen Libfunktionen für Fliesskommarechnung verwendete, wenn man 
vergass, dem Linker den richtigen Tipp zu geben. Meist merkten es die 
Leute, weil das RAM platzte.

von Detlev T. (detlevt)


Lesenswert?

Den Compilerschalter -Os (auf Größe optimieren) kennst du?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

In der aktuellen Version des Compiler ist das nicht mehr so — 
vorausgesetzt, der Compiler wurde adäquat konfiguriert: 
http://gcc.gnu.org/PR54461

D.h. auch ohne -lm werden immer die optimierten Routinen der AVR-LibC 
verwendet; in der libgcc.a sind sie nämlich nicht mehr vorhanden. 
Ausserdem wird -lm automatisch durch den Compiler gesetzt.  Grund ist, 
daß die libm.a float-Routinen enthält, die über math.h hinaus gehen, 
nämlich Operationen wie + und * welche zum Sprachkern gehören.

Daher muss man sich um das Setzen von -lm ebenso wenig kümmern wie um 
das Setzen von -lc oder -lgcc.

von Peter D. (peda)


Lesenswert?

Johann L. schrieb:
> In der aktuellen Version des Compiler ist das nicht mehr so

Viele haben nicht die Zeit und Lust, ständig der neuesten Version 
nachzujagen.
Es ist auch eine Frage der Zuverlässigkeit. Wenn viel Code und 
Bibliotheken mit einer bestimmten Compilerversion erstellt und getestet 
wurden, dann bleibt man möglichst lange dabei.
Z.B. der Keil C51, den wir benutzen, ist von 1995.

Der WINAVR-2010 braucht -lm.
Und da der Code ja um 3kB angestiegen ist, braucht er es auch.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:

> Viele haben nicht die Zeit und Lust, ständig der neuesten Version
> nachzujagen.

Na dann verwende eben alte Versionen.

von Markus M. (adrock)


Lesenswert?

...falls es noch keiner geschrieben hat:

Ein pragmatischer Ansatz ist:

Überlege wie genau das Ergebnis sein muss bzw. welchen Werteberiech a 
und b haben.

Angenommen, Dein Wertebereich wäre nicht größer als 0..655 und Du 
möchtest zwei Nachommastellen, dann nimmst Du für die Variablen (bis auf 
e) uint16_t und alle Werte *100 und am Ende machst Du dann ein

e = (c+50)/100;

Wenn man damit leben kann, eine Genauigkeit von z.B. 1/256 zu haben, und 
der Wertebereich 0..255 ist, kann man auch einfach alle Werte *256 
nehmen und im letzten Schritt /256, das ist für den Compiler SEHR 
einfach zu übersetzen.

Grüße
Markus

von Detlev T. (detlevt)


Lesenswert?

Markus M. schrieb:
> e = (c+50)/100;

Wenn a und b schon (Pseudo-) Fixkomma-Zahlen sind, also Integer mit Wert 
* Konstante (z.B. 100), genügt ein:
1
e = (a + b/2) / b;
Durch die Division hebt sich die Konstante ja schon weg.

von simso (Gast)


Lesenswert?

An alle die hier konstruktiv beigetragen haben:

das mit dem Double war gestern Abend natürlich ne "Schnapsidee" ;-)

So wie W.S. geschrieben hat muss ich  leider diese Division durchführen 
.

Habe die ganze Zeit AVR Studio 4 Benutzt nun habe ich mir das neue Atmel 
Studio 6 installiert und siehe da anstatt 40% Speicher braucht die 
Division nur noch 10% Speicher und dass kann ich in meinem 
Anwendungsfall verkraften;-).


PS: Zu den ersten Beiträgen: Wenn ich schon 20Jahre Erfahrung in C 
Programmierung hätte und so wie einige geschrieben haben ne hohe 
Kompetenz hätte müsste ich hier keine Postings zu diesem Thema 
durchführen.

Das nächste mal einfach nicht antworten oder etwas die Etikette wahren.

Danke!

von W.S. (Gast)


Lesenswert?

OK, das Problem ist erledigt.
Trotzdem noch ein Nachtrag von mir:

Michael schrieb:
> Was hat Float jetzt mit Nachkommastellen zu tun?

Wo in der Programmiersprache C gibt es überhaupt Nachkommastellen? Etwa 
bei char, int, long ? nee. nur in float bzw. double

Oder andersherum:
Teile mal 9899373 durch 10000012 und komme dabei drauf, daß der 
verwendete Referenzoszillator eben 10.000012 MHz hat und die zu 
vermessende Signalquelle 9.899274 MHz. In Assembler ist das gar kein 
Problem, da macht man sowieso alles zu Fuß, aber formuliere sowas mal 
gescheit in C - du Naseweis.

W.S.

von Hans W. (Firma: Wilhelm.Consulting) (hans-)


Lesenswert?

sachte, sachte!

du hast long double und die 3 complex typen vergessen...

wo ist überhaupt dein problem bei der floatingpoint-division?

73

von Michael (Gast)


Lesenswert?

W.S. schrieb:
> aber formuliere sowas mal gescheit in C - du Naseweis.

Wenn man das gescheit rechnen möchte, gibtst du deine Frequenzen z.B. in 
Hz an. Quotienten nahe 1 kannst du immer mit einer Reihenentwicklung 
deiner Division, die du nach dem liniearen Glied abbrichst, erschlagen.
Mit Float bekommst du deine Zahlen schon von der Genauigkeit her nicht 
mehr dargestellt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.