Teilen mit / ohne Floaten in C [geschlossen]

7

Unten ist die Hauptfunktion, die ich in C schrieb (für PIC18F8722 Mikroprozessor), zu versuchen, 2 Multiplexing-7-Segment-Anzeigen mit einer bestimmten Frequenz zu betreiben, die durch die vorzeichenlose int-Funktion get_ADC_value() eingestellt wurde. Die Anzeigen zeigen auch die aktuelle Multiplexfrequenz an. Dieser Frequenzbereich wird von #define auf den Bereich LAB_Fmin und LAB_Fmax festgelegt und muss skaliert werden, wenn get_ADC_value() von 0 auf 255 erhöht oder verringert wird.

Dieser Code funktioniert jedoch nicht, da ich glaube, dass es eine implizite Konvertierung von int nach float bei freq = gibt.

Die Herausforderung besteht darin, diesen Fehler mit Gleitkommazahlen zu beheben und eine Alternative zu finden, die nur ganzzahlige Typen verwendet ( int , char ...).

%Vor%     
Psi 24.10.2016, 06:25
quelle

5 Antworten

16

C ist so definiert, dass int s durch ganzzahlige Division geteilt wird, und nur wenn es einen Float gibt, "befördert" es zuerst andere int s zu float s. Beachten Sie, dass dies sogar passiert, wenn es einem float zugewiesen wird - wenn die rechte Seite alle int s ist, dann wird die Division ganzzahlig sein, und nur für die endgültige Zuweisung wird C int konvertieren Ergebnis zu float .

Also, mit Ihrer Linie:

%Vor%

Es hängt alles davon ab, was LAB_Fmax und LAB_Fmin sind. Es spielt keine Rolle, was freq oder x ist, weil der "Schaden" bereits aufgrund der Klammern erfolgt ist, die die Division zuerst zwingen.

Wenn diese LAB_F Variablen int s sind, ist der einfachste Weg, die Gleitkommadivision zu verwenden, einfach C zu sagen, dass Sie das wollen, indem Sie die Konstante 255 eine Fließkommazahl anstelle einer Ganzzahl verwenden ein Dezimalpunkt: 255. (oder 255.0 , um weniger subtil zu sein).

Wenn Sie nur Integer-Arithmetik verwenden möchten, ist der übliche Vorschlag, alle Ihre Multiplikationen vor allen Divisionen durchzuführen. Dies birgt natürlich das Risiko, dass das Zwischenergebnis überläuft - um das zu helfen, können Sie den Typ long verwenden. Definieren Sie Ihre Variablen LAB_F oder x als long und führen Sie die letzte Division durch:

%Vor%     
John Burger 24.10.2016, 06:37
quelle
10

Code Überprüfung:

  • unsigned int x, y, z; Vermeiden Sie die Verwendung von rohen Integer-Typen auf eingebetteten Systemen. Genaue Breitentypen von stdint.h sollten immer verwendet werden, damit Sie genau wissen, welche Größe Sie verwenden. Wenn Sie keinen Zugriff auf stdint.h haben, geben Sie diese Typen selbst ein.

  • float freq, delay; Fließkommazahlen sollten auf den meisten eingebetteten Systemen generell vermieden werden. Besonders bei 8-Bit-MCUs ohne FPU! Dies führt zu softwaredefinierten Fließkommazahlen, die unglaublich langsam und speicherintensiv sind. Es scheint keinen Grund zu geben, Floats in diesem Programm zu verwenden, es scheint, dass Sie in der Lage sein sollten, diesen Algorithmus mit uint16_t oder kleiner zu schreiben, es sei denn, Sie haben extreme Genauigkeitsanforderungen.

  • x = get_ADC_value(); Da Sie nur an 8 Bits des gelesenen ADC interessiert scheinen, warum nicht einen 8-Bit-Typ verwenden?

  • Bitte beachten Sie, dass binäre Zahlenliterale nicht Standard C sind.

  • ((LAB_Fmax) - (LAB_Fmin))/ 255 Das sieht fischig aus. Vor allem, sind diese ganzen Zahlen oder schwimmt? Was ist ihre Größe? Die Antwort auf Ihre Frage hängt davon ab. Indem Sie das Literal an 255.0f vertauschen, können Sie eine Konvertierung zum Floaten erzwingen. Aber bist du sicher, dass die Division 255 sein sollte? Und nicht 256?

  • i<(delay) . Sie sollten immer die Verwendung von Gleitkommaausdrücken innerhalb von Schleifenbedingungen vermeiden, da dies die Schleife unnötig langsam macht und möglicherweise zu Ungenauigkeiten bei Gleitkomma-Fehlern führen kann. Auch die Klammer erfüllt keinen Zweck.

Insgesamt leidet Ihr Programm unter "schlampigem Tippen", was bedeutet, dass der Programmierer sich keine Gedanken darüber gemacht hat, welche Typen in jedem Ausdruck verwendet werden. Beachten Sie, dass Literale auch Typen haben. Implizite Conversions können dazu führen, dass viele dieser Ausdrücke auf zu große Typen berechnet werden, was für den PIC sehr schlecht ist. Ich empfehle das Lesen von "Balancing", aka die üblichen arithmetischen Konvertierungen .

Dieses "schlampige Tippen" wird dazu führen, dass Ihr Programm sehr aufgebläht und langsam wird, weil nichts gewonnen wird. Sie müssen daran denken, dass PIC möglicherweise die am wenigsten Code-effiziente MCU ist, die immer noch hergestellt wird. Wenn Sie C-Code für eine 8-Bit-MCU schreiben, sollten Sie Typen vermeiden, die größer als 8 Bit sind. Insbesondere sollten Sie 32-Bit-Ganzzahlen und Gleitkommazahlen wie die Pest vermeiden.

Ihr Programm skaliert alle Daten auf Typen um, die das Denken für den Programmierer erleichtern. Dies ist ein häufiger Konstruktionsfehler - stattdessen sollte Ihr Programm Typen verwenden, die für den Prozessor einfach zu verwenden sind. Zum Beispiel könnten Sie anstelle von Millisekunden Timer-Ticks als Einheit verwenden.

    
Lundin 24.10.2016 08:33
quelle
6

Sie haben Recht bezüglich der Ganzzahldivision. Wechseln Sie zu

%Vor%     
Mitch Wheat 24.10.2016 06:26
quelle
4
%Vor%

Dies ist in der Tat eine implizite Umwandlung in Ganzzahl, und Sie tun Integer-Division, um das zu tun.

Das liegt daran, dass 255 ein Integer-Literal ist.

Ändere es in 255.0 , um ein doppeltes Literal zu sein, was gut zu deiner Berechnung passen sollte.

Wenn Sie genauer sein wollen, können Sie sogar ein Fließkomma-Literal verwenden, wie 255.0f oder eine explizite Umwandlung wie (float)255 .

Ihr Code könnte dann so aussehen:

%Vor%

Oder das:

%Vor%     
Magisch 24.10.2016 06:32
quelle
3

Mathematische Operationen mit Ganzzahlen ergeben standardmäßig auch eine Ganzzahl, Sie müssen also eines der Literale als double / float

ausgeben %Vor%

oder Cast (float)

Wie viele andere Zustände ist die erste Option am häufigsten implementiert.

    
quelle