Forum: Mikrocontroller und Digitale Elektronik unsigned long --> float


von Norbert (Gast)


Lesenswert?

Mein math. Problem:

vier Variable sind definiert. (für ATmega128)

unsigned long al = 10034456;
unsigned long bl = 1254299;
float af;
float bf;

// Die Umwandlung soll hier geschehen:

af = al;
bf = bl;

// Das Ergebniss ist nicht ganz optimal.
// In af steht der Wert 1,00345E+7,
// und in bf steht 1,2543E+6

// Der C-Compiler CodeVision rechnet nur mit max. 5-stelliger
// Genauigkeit.

Kennt jemand eine Möglichkeit diese Einschränkung zu umgehen?

Vielen Dank    Norbert

von crazy horse (Gast)


Lesenswert?

vielleicht nur ein Darstellungsproblem der float Zahl? Code-Vision 
arbeitet (wie alle anderen Compiler auch die ich kenne) mit 23bit 
Mantisse.

von dieter (Gast)


Lesenswert?

Hallo,
entweder mit long rechnen und am Ende der
Berechung den Nachkommateil errechnen.
Also vor dem Rechnen mit 1000 erweitern und nach der
Berechnung wieder durch 1000 teilen.

Eine weite Möglichkeit ist die Verwendung von double,
aber das ist evtl. mit dem Compiler nicht möglich.
Selbst wenn alles kompiliert, kann es passieren, das immer noch float 
verwendet wird.
Also immer noch 16-Bit.

Dieter

von Matthias (Gast)


Lesenswert?

Hi

float läßt sich fast immer verhindern. Ich sehe keinen Sinn darin auf 
8-Bit Maschinen mit float zu hantieren. Selbst auf dem M16C vermeide ich 
das wo es geht. Meist rechnet es sich genausogut nur schneller mit int 
bzw. long.

Matthias

von Michael (Gast)


Lesenswert?

Hallo Norbert,
letzlich wird Dir nicht der interne float-Wert angezeigt, sondern das, 
was printf daraus macht. Bei float ist die 7. Dezimalstelle ungenau, 
sechs Stellen sollten stimmen. Bei 1.2543E+6 wird m.E. nur eine '0' beim 
Formatieren unterdrückt, nachdem zuvor die letzte '9' richtig gerundet 
wurde. Ich sehe insgesamt keinen Mangel bei Deinen floats.

von Norbert (Gast)


Lesenswert?

Ich möchte mein Problem etwas verdeutlichen:

meine Variablen sind:

unsigned long al = 10034456;
unsigned long bl = 1254299;
float af;
float bf;

Wenn ich die Division der Zahlenwerte von al / bl mit dem Taschenrechner 
ausrechne, so bekomme ich das Ergebniss 8,000051...

Wird jedoch die Division der float-Werte af / bf im Controller
durchgeführt, so bekomme ich das Ergebniss 8,000079...
Dieses Ergebniss ist nicht brauchbar. Ich benötige eine Berechnung mit 
6-stelliger Genauigkeit(ANSI-C-Standart).

Mein Compiler(CodeVision), und alle anderen AVR-Compiler machen bei 
float-Berechnungen nur 5-Stellen genau.

Im weiteren Verlauf des Programmes werden die  Berechnungen

periode = 8,000079 * 1e-7 und frequenz = 1 / periode durchgeführt.


Vielleicht finde ich einen Weg, die von Dieter und Matthias 
vorgeschlagene long-Berechnung durchzuführen.


Schönen Gruß   Norbert

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Hallo Norbert,

ich habe testweise mal Deine Berechnung auf nem 8051 laufen lassen:

unsigned long test( unsigned long a, unsigned long b )
{
  float af, bf;
  af = a;
  bf = b;

  return  af / bf * 1e8;
}


void main( void )
{
  unsigned long al = 10034456;
  unsigned long bl = 1254299;

  al = test( al, bl );
  for(;;);
}

Da kommt als Ergebnis richtig 800005120 raus.
Warum alle AVR-Compiler das nicht können sollen, ist mir unverständlich.

Da bleibt wohl nur, es in Assembler zu machen. Da kannst Du ganz leicht 
beliebig genaue Ganzzahldivisionen nach der üblichen 
Schieben-Testen-Abziehen-Methode machen.
Ich habs z.B. mal für einen Frequenzzähler mit 56 Bit / 24 Bit gemacht 
(siehe Anhang).


Peter

von Michael (Gast)


Lesenswert?

Bei solchen Problemen werde ich immer neugierig: ein Turbo-C Compiler 
aus der 'Steinzeit' liefert mir Dein Taschenrechnerergebnis; ein 
C-Compiler einer Firma mit drei Buchstaben, die mit 'I' anfängt, liefert 
mir ebenfalls die 8.000051. Zumindest von WinAvr würde ich auch ein 
korrektes Ergebnis erwarten.

Deine Berechnungen mit long zu machen ist kippsch bezüglich eines großen 
Meßbereiches - float erleichtert dies erheblich. Falls Du nur 
Frequenz/Periode messen möchtest, nutzt Dir vielleicht 
www.mino-elektronik.de/fmeter/fm_software.htm. Dort findest Du .c-Quelle 
+ .hex-Code allerdings für einen 2313.

von Norbert (Gast)


Lesenswert?

@Michael: Sicherlich gibt es Compiler die das gewünschte Ergebniss 
liefern. Aber weder die 'Steinzeitcompiler' noch der IAR ünterstützten 
den AVRmega128!

Für mich entwickelt sich das Ganze zur Farce. Da bietet mir der mega128 
die optimale on-Board Hardware, wegen fehlender
SW-Tools kann ich ihn aber nicht einsetzen.

Als Alternative bleibt mir nur der C166-Compiler von Keil. Denn als 
Controllerersatz für den m128 kann ich nur den XC161CJ von Infineon 
einsetzen.

Heul...


Trotzdem, danke für Eure Meinung!    Norbert

von Michael (Gast)


Lesenswert?

Hallo Norbert,
der IAR-Compiler unterstützt den 128 voll (V2.xx). Auch die Version 1.xx 
erzeugt Code dafür, ohne allerdings die neuen Befehle zu nutzen. Die 
Tage hatte ich hier auch die Zeiten für fmul/fdiv mit unter 50us bei 
12MHz angegeben, was einige Gemüter vor 'Erstaunen' aufregte. Das Teil 
kostet aber richtig Kohle.
Wenn der C166 für Dich keine Probleme bereitet, nutze ihn.
Zuvor würde ich aber unbedingt WinAvr testen, der auch korrekt rechnen 
müßte. Frag doch 'mal im Forum AVR-GCC nach der Rechengenauigkeit; da 
wirst Du sicherlich kompetente Leute finden, die Dein Beispiel 'mal eben 
schnell' rechnen lassen können.

von Norbert (Gast)


Lesenswert?

Michael,

laut IAR.com wird der mega128 nicht von Workbench unterstützt.

Da ich eh die komplette C166-Umgebung von Keil (µVision2) besitze würde 
es wenig Sinn machen noch einmal eine sehr teure IDE zu kaufen.

Was WinAvr betrifft, so ist es merkwürdig still hier im Forum.
Ich gehe davon aus, daß User des AVR-GCC-Forum hier im Allgemein-Forum 
auch mal 'Querlesen'.


Schönen Gruß     Norbert

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.