Integer und Float

Hallo,

ich habe eine Problem, bei dem ich vermute, dass es auf einen Deklarationsfehler zurück zu führen ist.

Folgende Situation scheint ein unerwartetes Ergebnis zu führen

float aFloat = 90;
int Ergebnis; // Ich brauche als Ergebnis eine ganze Zahl

Egebnis = aFloat / 100 * 256;

Wenn ich das Ergebnis wie oben berechnen lasse, verhält sich das Programm unerwartet.
Trage ich aber das Ergebnis 230 direkt ein, funktioniert es!

Ich vermute, dass aFloat vom Compiler auf Int optimiert wird. Kann mir jemand helfen!

Vielen Dank für eure Aufmerksamkeit

LG Thomas

Mache aus

float aFloat = 90;

mal

float aFloat = 90.0;

Dann ist das auch eine Float die der Kompiler nicht weg haut.
Nur so als test.
Gruß
DerDani

Vielen Dank für die super schnelle Antwort. Ich muss mein Programm noch ein klein wenig anpassen, dann werde ich es heute Abend gleich mal probieren. Schade, dass die Arduino-IDE kein Debugging unterstützt!

LG Thomas

void setup() {
   Serial.begin(9600);

   float f = 90;
   int i = f / 100 * 256;

   Serial.println(i);
}
void loop() {}

Bei mir wird 230 ausgegeben.
Welche IDE und welchen Arduino verwendest du ?

Wenn man sich das Ergebnis des vorigen Beispiel-Codes ansieht (avr-objdump -d) , merkt man, dass das schon der Compiler richtig macht. Auf dem Arduino ist da überhaupt kein Gleitkomma-Code:

 5b8:   4a e0           ldi     r20, 0x0A       ; 10
 5ba:   66 ee           ldi     r22, 0xE6       ; 230
 5bc:   70 e0           ldi     r23, 0x00       ; 0
 5be:   80 e0           ldi     r24, 0x00       ; 0
 5c0:   90 e0           ldi     r25, 0x00       ; 0
 5c2:   0e 94 6f 01     call    0x2de   ; 0x2de <_ZN5Print11printNumberEmh.constprop.11>

Ich vermute, dass aFloat vom Compiler auf Int optimiert wird.

Und ich vermute, dass du da irgendeinen Fantasiecode zeigst, welcher diesen "Fehler" gar nicht hat.
Bin mir sogar sicher, dass du das gezeigte Beispiel noch nicht mal selber getestet hast.

Du buddelst auf der falschen Baustelle.

Der tatsächliche Fehler liegt wie immer im verborgenen Teil des Sketches.

Wenn ich das Ergebnis wie oben berechnen lasse, verhält sich das Programm unerwartet

Wie? Was tut es?

Hallo,

vielen Dank für die zahlreichen Kommentare. Lieber Combie, eigentlich hast du da gar nicht sooooo unrecht. Ich habe den Teil meines Programmes aus seinem Kontext herausgenommen, bei dem ich den Fehler vermutet habe. Den Begriff Fantasie zu verwenden, halte ich jetzt nicht gerade für sehr sachlich. Wenn ich nur Fantasiefragen stellen würde, würde ich natürlich auch nur Fantasieantworten bekommen. Was hätte ich davon? Aber ich nehme deine Kritik sehr gerne an und werde mich in Zukunft bemühen mein Problem verständlicher zu beschreiben.

LG Thomas

Hallo,

für ein besseres Verständnis, worum es überhaupt geht, sende ich mal den Code

#include "BlinkFireMillis.h"
#include "CandleLight.h"

unsigned long beginIntervall;                 // Start eines neuen Intervalls in Millisekunden 

long lightIntervallLength;                    // die Länge eines aktuellen Intervalls
uint8_t newBrightness;                        // die neue Endhelligkeit beim Fading

uint8_t stepBrightness;                       // Einzellschrittgröße beim Fading
uint8_t currentBrightness;                    // aktuelle Brightness

CandleLight candleLight;

void setup() { 
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  randomSeed(analogRead(0));        
}

void loop() { 
  candleLight.Flickering();
}
#ifndef BlinkFireMillis_h
#define BlinkFireMillis_h

#include <arduino.h>
#include "FastLED.h"

// How many leds in your strip?
#define NUM_LEDS 1

#define DATA_PIN 6

// Define the array of leds
CRGB leds[NUM_LEDS];

#endif
#ifndef CandleLight_h
#define CandleLight_h

#include "BlinkFireMillis.h"

class CandleLight {
 private:

  int number;                                   // Position in der Stripe, beginnend mit  0               
  unsigned long beginIntervall;                 // Start eines neuen Intervalls in Millisekunden 
  long lightIntervallLength;                    // die Länge eines aktuellen Intervalls
  uint8_t newBrightness;                        // die neue Endhelligkeit beim Fading
  CRGB color;

  public:
  CandleLight() {
    CandleLight(0, CRGB::OrangeRed);
  }
  
  CandleLight(uint8_t number, CRGB color) {
    this->number = number;                      
    newBrightness = random(50,255);
    lightIntervallLength = random(100,300);
    FastLED.setBrightness(newBrightness);
    this->color = color;
    leds[number] = color;
    FastLED.show();
    beginIntervall = millis();
  }

  void Flickering() {   
    if (millis() > beginIntervall + lightIntervallLength) {
        newBrightness = random(50,255);
        lightIntervallLength = random(100,300);
        FastLED.setBrightness(newBrightness);  
        FastLED.show();
        beginIntervall = millis();
    }  
  }
};
#endif

Meine Absicht ist es in CandleLight.h FastLED.setBrightness(newBrightness); durch in etwa so etwas zu ersetzen
fadeLightBy (uint8_t fadefactor), damit ich die Helligkeit für jede einzelne LED regeln kann.

Das hat aber nicht funktioniert, weil als Resultat gar nichts mehr geflackert hat, bzw. die LED leuchtete konstant.

fadeLightBy braucht als Parameter x%/100256 z.B. 25% Leuchtstärke 25/100256=64

25/100 würde im Falle von INT vermutlich wohl 0 ergeben. Deshalb meine Vermutung!

Da FastLED.setBrightness die Einstellung aller LED's betrifft, nutzt mir diese Funktion nichts. Ich möchte jede LED einzeln und im eigenen Rhythmus flackern lassen.

Für eine LED funktioniert der Programmcode (FastLED.setBrightness) natürlich, aber eben nicht mehr für jede Instanz im eigenen Rhythmus.

Vielen Dank für eure Aufmerksamkeit

LG THomas

CandleLight() {
    CandleLight(0, CRGB::OrangeRed);
  }

Das macht überhaupt nicht was du denkst. Das erzeugt ein temporäres Objekt das gleich wieder verworfen wird

Was du willst nennt sich "delegating constructor":
https://www.learncpp.com/cpp-tutorial/8-6-overlapping-and-delegating-constructors/

Den Begriff Fantasie zu verwenden, halte ich jetzt nicht gerade für sehr sachlich.

Ok, ich hätte auch eher "verarscht" sagen wollen.
(aber mich nicht getraut)

Da macht man sich extra die Arbeit, testet dein verstümmeltes Fragment, korrigiert den Syntaxfehler und dann:
Es zeigt nicht den Fehler.

Ein klein bisschen ärgerlich, das ist.
Da frage ich mich doch: Will er/sie/es überhaupt Hilfe?
Warum fragt es Fragen, die nicht funktionieren?
Oder: Wieso mache ich mir überhaupt Mühe?

25/100 würde im Falle von INT vermutlich wohl 0 ergeben. Deshalb meine Vermutung!

Da muss man nicht vermuten, sondern die Sprache, welche man verwendet, lernen.
In jedem guten C/C++ Buch steht das auf den ersten Seiten.

Also:
Wenn du float Operationen wünscht, dann musst du den Kompiler zwingen diese auch durchzuführen.

Viele Möglichkeiten es gibt, hier 2 davon:
25.0/100.0
float(25)/float(100)

Ok, ich hätte auch eher "verarscht" sagen wollen.

Aber warum so destruktiv? Ich habe doch kein Interesse daran jemanden zu verarschen. Ich habe doch weiter nichts getan als eine leichtfertig formulierte Frage zu stellen. Entspanne dich bitte wieder! Natürlich habe ich auch erkannt, dass viele wohlmeinende Antworten dabei waren. Denen danke ich natürlich auch sehr. Und wie gesagt, ich werde in Zukunft versuchen meine Fragen präziser zu formulieren.

Also:
Wenn du float Operationen wünscht, dann musst du den Kompiler zwingen diese auch durchzuführen.

Vielen Dank! Aber dann war doch meine Vermutung gar nicht so unberechtigt!

Das macht überhaupt nicht was du denkst

Vielen Dank für den Hinweis und den Link. Da meine Variante so funktioniert hat, ist mir der vermeintlich unsaubere Programmierstil gar nicht aufgefallen. Aber wie kommt dann eigentlich die Information CRGB::OrangeRed in meine erzeugte Instanz? Zumindest hat dieser Aufruf die gewünschte Information weitergegeben und das erzeugte Objekt brauche ich dann nicht mehr.

Also habe ich nun die folgende Schreibweise verwendet

CandleLight() : CandleLight(0, CRGB::OrangeRed) {   }

Sie sieht irgendwie eleganter aus und ich habe wieder etwas dazugelernt.

Hochachtungsvoll
Thomas

Ich habe doch weiter nichts getan als eine leichtfertig formulierte Frage zu stellen.

Iss klar....

Du darfst leichtfertig sein, und ich darf nicht von deiner "leichtfertigkeit" genervt sein.
Und es dir natürlich auch nicht sagen.

Iss klar....

Aber dann war doch meine Vermutung gar nicht so unberechtigt!
....
Ich vermute, dass aFloat vom Compiler auf Int optimiert wird. Kann mir jemand helfen!

Nicht vermuten, sondern die Sprache lernen, welche du verwendest.
C++

Deine Vermutung ist falsch!
Denn das hat nichts mit optimieren zu tun, sondern ist in der Sprachdefinition so verankert.
Auch wenn das für dich das gleiche zu sein scheint, macht es für mich doch einen großen Unterschied!

float aFloat = 90;

// vs.
float aFloat = 90.0;

Das ist übrigens wirkungslos

Denn "float aFloat = 90;" führt zu einem impliziten Cast
Vergleichbar mit diesem:"float aFloat = float(90);"

Besser/Moderner als "float aFloat = 90;" wäre "float aFloat {90.0};"

Alles das kann man in einem modernen C++ Buch nachlesen.
Übrigens: Ein Forum ersetzt kein Grundlagenbuch.

Gelernte Grundlagen ersparen einem viele Irrtümer, falsche und richtige Vermutungen
(und damit vielleicht so gar das ein oder andere Fettnäpfchen im Forum)

Hallo Combie,

Du darfst leichtfertig sein, und ich darf nicht von deiner "leichtfertigkeit" genervt sein.
Und es dir natürlich auch nicht sagen.

Iss klar....

Es kann manchmal nicht schaden die Regeln des Anstandes und Taktes zu bewahren. Das steht allerdings in keinem Grundlagenbuch, das du vorher lesen könntest!

Übrigens: Ein Forum ersetzt kein Grundlagenbuch.

Ich habe es nun verstanden. In Zukunft werde ich also Grundlagenbücher lesen, bevor ich mal eine simple Frage ins Forum stelle.

Deine Vermutung ist falsch!
Denn das hat nichts mit optimieren zu tun, sondern ist in der Sprachdefinition so verankert.
Auch wenn das für dich das gleiche zu sein scheint, macht es für mich doch einen großen Unterschied!

Der Hintergrund und die Motivation sind doch in diesem Zusammenhang eigentlich irrelevant.

Alles das kann man in einem modernen C++ Buch nachlesen.

Das setzt aber die Gewissheit voraus, dass avr-gcc alle Feature eines modernen C++ unterstützt. Es könnte ja Mikroprozessor-spezifische Unterschiede oder Einschränkungen geben. Darüber war ich mir bisher nicht im Klaren. Inzwischen weiß ich, dass avr-gcc zum modernen C++ kompatibel ist.

Mehr möchte ich eigentlich nicht mehr zu dieser Angelegenheit "sagen". Wenn du dich dennoch weiterhin spiegeln möchtest, erwarte bitte von mir keine Reaktionen mehr.

Hochachtungsvoll
Thomas

SakuraHanami:
Da meine Variante so funktioniert hat, ist mir der vermeintlich unsaubere Programmierstil gar nicht aufgefallen.

Nur weil etwas kompiliert heißt das nicht dass es funktioniert. Das war nicht unsauber, sondern falsch. In einem Konstruktor selbst kann in C++ nie etwas initialisiert werden. Wenn man nichts besonderes macht findet die Initialisierung vorher statt und zwar auf Defaultwerte (i.d.R. Null). Im Konstruktor-Körper kannst du dann Dinge nur neu zuweisen.

Siehe auch Initialisierungslisten. Und die Initialisierung von Konstanten damit

Zumindest hat dieser Aufruf die gewünschte Information weitergegeben

Keine Ahnung was da abgelaufen ist, aber weitergegeben wurde da nichts. Ein Aufruf einer Methode alleine gibt nichts weiter und Konstruktoren haben auch gar keine Rückgabewerte

Es könnte ja Mikroprozessor-spezifische Unterschiede oder Einschränkungen geben.

GCC kann eher mehr. Es gibt da eine ganze Reihe Erweiterungen mit zum Teil sehr nützlichen zusätzlichen Dingen. z.B. lokale Arrays variabler Länge oder Bereiche bei switch/case
Siehe "GCC Extensions"

Wenn GCC etwas nicht kann liegt das daran dass deine Version aktuelle Standards wie C++14 oder C++17 noch nicht vollständig unterstützt. Manche Features sind da teilweise noch nicht implementiert. Die Arduino IDE hinkt da oft auch etwas hinterher. Da kommt es dann darauf an welche Version der Toolchain du verwendest. Das kann man aber Online auch genau nachlesen

Ein großer Unterschied zu C++ Büchern ist dass es auf AVRs keine Standard Template Library gibt