Hallo und guten Morgen,
ich habe folgendes Problem mit float Werten. Ich möchte zum Beispiel von einem float Wert 0.01 die Nullen ermitteln. Wie kann ich die Anzahl der Nullen berechnen?
|
Anzeige
|
Nullen von float Wert ermittelnHallo und guten Morgen, ich habe folgendes Problem mit float Werten. Ich möchte zum Beispiel von einem float Wert 0.01 die Nullen ermitteln. Wie kann ich die Anzahl der Nullen berechnen? Kommt drauf an. Die Zahl in einen String umwandeln (Funktion dtostrf()) und die Nullen zählen.
Gast
#7397053
zahl = 0.01; anzahlDerNullen = ceil( -log10( zahl ) );
deine Fragestellung ist zu unspezifisch. 0,01 --> 2 Nullen total, davon 1 Vorkommastelle, 1 Nachkommastelle 10,0 --> 2 Nullen Total, davon 1 Vorkommastelle, 1 Nachkommastelle 1,0 -> 1 Null total, davon 0 Vorkommastellen, 1 NAchkommastelle 1,01 --> 1 Null total, davon 0 Vorkommastellen, 1 Nachkommastelle 100,01 --> 3 Nullen total, davon 2 Vorkommastellen, 1 Nachkommastelle 0,0101 --> 3 Nullen total, davon 1 Vorkommastelle, 2 Nachkommastellen WAS Genau möchtest du also ermitteln, WARUM möchtest du das ermitteln, WOMIT (welche Programmiersprache) möchtest du das ermitteln? Der Funktion soll auf einem 32bit Mikrocontroller eingesetzt werden. Programmiersprache C.
Ja... Soweit mir bekannt, nennt sich das notwendige Verfahren: Zählen!
Gast
#7397068
Ich hatte Deine Frage so verstanden, dass Du die führenden Nullen bei Zahlen kleiner als 1 berechnen wolltest. Wenn es etwas anderes ist, solltest Du es schreiben Ok ich hab mich nicht richtig ausgedrückt. Beispiel: 0.001 Ich möchte die Zahlen vor der 1 ermitteln. Hallo, du willst wahrscheinlich die Vornullen, also die Stelle des Kommas wissen. Float Werte liegen in IEEE-Format vor. Da suchst du dir den Exponenten, berücksichtigst das Zweierkomplement und die Zweier Basis und hast die Größenordnung. Sollte mit Bitmanipulationen und Grundrechenarten (ohne log-Funktion) funktionieren.
Gast
#7397072
Genau das hab ich beantwortet. Viel Erfolg mit dem Code
Du könntest die Zahl so oft mit 10 multiplizieren, und dann auf >1 prüfen. Die Anzahl der Multiplikationen mit 10 ergeben die führenden 0er. Also irgendwie so (ungetestet):
Na dann musst du hinten anfangen und alle Nullen zählen, bis du entweder das Zeichen '.' oder den Stringanfang findest. Erstmal vielen Dank!
Guter Einwand. sollte sich aber mit abs() lösen lassen.
Wo auch immer "vorne" ist bei einer Zahl... Du meinst vermutlich die Nullen, die links von der 1 stehen. Das sind in diesem Beispiel 3 Stück. Oder meinst du die Nullen zwischen dem Komma und der ersten "ungleich 0" Stelle, was dann 2 wären?
Das Problem dabei ist, dass es eben eine Floatzahl "gleich 0,01" mit allerhöchster Wahrscheinlichkeit nicht gibt. sondern das ist ein binäres Bitmuster, das z.B. 0,01000001 oder 0,00999999 darstellt und nur von der Ausgaberoutine zur augenfreundlichen 0,01 formatiert wird. Und jetzt kommt der Witz: wenn ich diese mit 1x '0' zwischen Komma und '1' angezeigte reale 0,009999999 mit 10 multipliziere, dann bekomme ich evtl. heraus, dass die angezeigte 0,01 eben 2x '0' zwischen Komma und '9' hat. Das ist natürlich eine Betrachtung eines "Ausnahmefalls", aber wegen solcher nicht bedachten "Ausnahmefälle" funktionieren manche Geräte manchmal seltsam oder unerwartet oder gar nicht. Letztlich ist wieder mal die Frage: was willst du denn mit deiner Lösung machen? Eine Floatzahl ist sowieso intern auf 1.xxxx exp xx normiert, und das shiften macht der Exponent. Also muss man nur den exponent auswerten
Jaja, das ungesunde Halbwissen. Dumm nur, daß die interne Darstellung zur Basis 2 erfolgt, der OP aber nach den Nullen im Dezimalsystem fragt.
Allerdings ist das 1.xxxx eine Binärzahl und der TO möchte eine Dezimalzahl. Deshalb muss man das xxxx durchaus mit einrechnen, weil die bei jeder Zehnerstelle anders ist. Und was man mit den Progrämmchen auf der HP auch nachvollziehen kann: Wenn ich jetzt die 0,001 in eine Hex-Zahl umrechne erhalte ich 3A83126E Und wenn ich die 3A83126E wieder umrechne, dann erhalte ich (wie von mir vermutet) nicht 0,001 sondern 0,0009999999310821295 Man kann statt 3A83126E auch 3A83126F nehmen und erhält dann 0,0010000000474974513 Aber wie auch immer: eine 0,001 kann binär nicht exakt dargestellt werden.
Die Lösung hatte Falk B. doch schon ober genannt:
Einfach konsistent überall die gleiche Routine zur Umwandlung in die Dezimaldarstellung benutzen.
Schon, aber es kam aber eben auch noch ein augenscheinlich "einfacher" aber im Detail tückischer Vorschlag danach.
Nein, die hatte Robert G. (robert_g311) 20.04.2023 12:02 mit der Multiplikation genannt, wobei die Vorgaben bezüglich des Wertebereiches vom TO einfach noch zu unscharf sind. Da fällt dann auch die interne Zahlendarstellung nicht negativ auf, da 10.0 als Fließkommawert auch binär eindeutig ist. Wenn sich die 0.1 ab einer Stelle als 0,0999 entpuppt: bei der Multiplikation wird das "enttarnt". Erst in Strings zu wandeln und dann Zeichen zu suchen ist doch, auf Arduino Niveau den Programmspeicher vollzustopfen und ein weiteres 'delay' zu programmieren.
Mir gefällt die Lösung von Justin S. (derwer). Python3:
Oder in C:
Ich vermute hinter dem frommen Wunsch mal wieder einen Lösungsweg, den der TO sich selbst im stillen Kämmerlein erarbeitet hat, nämlich irgend etwas wie: "Jetzt muss ich nur noch die Anzahl der Nullen ermitteln, um die Zahl so und so formatiert ausgeben zu können!" Es wäre besser gewesen, zu formulieren, was er am Ende damit eigentlich erreichen will. Dann hätte man ihm einfach sagen können: "Mach das mit printf und dem folgenden Format und Du bist fertig".
log10 ist schon heftige Kost, wenn es um einen kleinen Mikrocontroller geht. Der TO hat leider nicht verraten, ob die "Ermittlung" auf einem ATTiny13 oder Großrechner erfolgen soll.
Wandele die Zahl gar nicht erst in eine Dezimalzahldarstellung um. Mache dir zu Nutze, dass Float Zahlen normalisiert im Speicher stehen und es also reicht, wenn du direkt den Exponenten auswertest.
Das ist doch ein ganz allgemeines Problem bei FP. Nicht nur theoretisch. Mehrwertsteuer auf einzelnen Rechnungen funktioniert. Mehrwertsteuer in der Bilanz wird falsch berechnet. Reklamation, weil ein Cent fehlt. Floatingpoint kannst du eh nur nutzen, wenn es ausreicht, dass es dezimal immer konsistent falsch dargestellt wird. He S.:
Frank M.:
Von 32 Bit Microcontroller war die Rede. Da kann man etwas Rechenpower, wenn nicht sogar FPU voraussetzen. Aber ich gebe Dir recht in Deiner Annahme, daß ein ganz trivialer Wunsch des TO dahintersteckt, nämlich die Frage nach formatierter Ausgabe. Vielleicht verrät er sein Ansinnen.
Funktioniert halt nicht. Dank float ist das Ergebnis nicht korrekt, log10(10000.0) liefert nicht unbedingt 4 sondern gerne mal 3.999999987 "Aus solchem code besteht das halbe Internet, nie getestet und nicht mal überlegt". Und dann gab es da noch floor und ceil.
Nein, es reicht eben nicht, weil in der Mantisse der Zahl im µC kein Dezimalwert, sondern ein Binärwert abgelegt ist. So ist logischerweise auch der Exponent ein binärer und kann nur 2^x abspeichern. Und weder 10 noch 100 noch 1000 noch sonst ein 10^y lässt sich damit abbilden. Ich meine, das hier im Thread bereits mit Bildern grundlegend klar dargestellt zu haben. Wenn man allerdings die Sache wirklich schlau angeht, dann rechnet man im µC nicht im Zehn-Finger-System, sondern controllerfreundlich im Dual-System (z.B. auch bei Puffergrößen). Und dann reicht es tatsächlich aus, den Exponenten auszuwerten. Wenn man sich diese Dual-Denkweise mal eingehend angeeignet hat, dann braucht man auf einmal nicht mehr den schnelleren µC und auch die Programmgröße wird auf magische Weise kompakter.
Gast
#7397411
Hm, ein 32bit Mikrocontroller sollte mit den log10 gerade so zurechtkommen, oder? Von "effizient" war keine Rede in der Frage. Standard bei Antworten sollte dann einfach und verständlich und funktionierend sein. Hier im Exponenten eines float "herumzuwurschteln" ist absolut kontraproduktiv. Und Wandlung in einen String ist ebenfalls "heftige Kost", und in einer Schleife zu "zählen" ebenso ...
Wenn aber (aus welchen nicht nachvollziehbaren Gründen auch immer) die Anzahl der Nullen in genau diesem String interessant ist z.B. weil da steht
dann bleibt einem nichts andere übrig, als genau die Nullen in genau diesem String zu zählen... Der Verdacht besteht, daß es um die Ausgabe eines Float-Wertes auf einem LC-Display geht, bei dem führende Nullen unterbunden werden sollen. Darum nämlich geht es im anderen Thread des Threadstarters, und so überaus präzise, wie er seine Problemstellungen beschreibt, kann es sehr, sehr gut sein, daß es sich letztlich um das gleiche Thema handelt.
Natürlich geht es das. Es ist ein prima Beispiel für ein XY-Problem: "Ich habe Aufgabe X aber weiß nicht, wie ich sie lösen soll. Aber wenn ich Aufgabe Y lösen könnte, dann würde ich vielleicht auch X schaffen. Also gehe ich mal los und frage das Forum nach Y." Blöderweise ist Y vollkommen esoterisch (es tritt ja auch gar nicht als eigenständiges Problem auf). Er kriegt also entweder keine oder nur abgehobene Antworten auf seine Frage. Und das Beste: es stellt sich heraus, daß die nicht dabei helfen, Problem X zu lösen. Ich glaube der TE geht sogar noch einen Schritt weiter. Nachdem sein Problem Y nicht so richtig was gebracht hat, probiert er es jetzt mit Z. Denn ein Ausgabeproblem hat er ja nicht (oder ich sehe es nicht). Er sagt er hat 8 Stellen. Seine Beispielwerte habe aber immer nur 4 oder 5 Stellen. Die passen also locker auf sein Display. Zur Not halt mit einer Null vor dem Dezimalpunkt und noch ein paar Nullen dahinter. Es wird nicht klar, was er eigentlich will. Will er den Dezimalpunkt immer an der gleichen Stelle? Oder immer genau 5 gültige Stellen (die erste natürlich von 0 verschieden) und die Angabe eines Exponenten? Oder soll der Wert mit SI Prefixen dargestellt werden (wissen schon: µ, m, k etc.) und so skaliert werden, daß immer zwischen 1 und 3 Stellen vor dem Dezimalpunkt sind? Fragen über Fragen.
Ja, und wenn schon. Erstens ist es nicht float sondern double, zweitens macht ceil() in jedem Fall eine 4 draus. Und gib mir ein Beispiel, wo log10(10000.0) "gerne mal" 3.999999987 liefert.
Es war der feine Hinweis, das ceil() hier wohl falsch ist und floor() lauten sollte. Und Rundungsfehler gibt es bei double genau so wie bei float. Da transzendale Funktionen per Annäherungsrechnungen, z.B. Reihenentwicklung oder CORDIC, berechnet werden, sind Rundungsfehler da normal. Selbst wenn ein Wert bei der dezimalen Ausgabe als 4.0000000 dargestellt wird, heisst das noch lange nicht dass das interne Ergebnis im Binarsystem nicht 3.99999999987 ist und von floor() auf 3 abgerundet wird. Wie jung auch immer du bist, offensichtlich noch zu jung für Erfahrung im Programmieren.
Eben! Deshalb runden Ausgaberoutinen auch kaufmännisch. Ein halber Stellenwert wird vorm Abrunden aufaddiert (z. B. + 0.005 für %.2f) bzw. vorzeichengemäß subtrahiert.
Die 4 bezog sich auf das von Dir gegebene Beispiel. (10000.)
transzendentale Funktionen, heißt es. Rundungsfehler bestreite ich auch nicht. Gerade deshalb ja ceil(). Aber in dem Bereich so kleiner Abweichungen liefern floor() und ceil() das gleiche Ergebnis.
Schön, daß man auf diese Weise jung bleiben kann. Ich glaube, ich habe mehr Jahre C (seit 1979) auf dem Buckel als Du.
Schon besser, aber mit Zähnen hat das nichts zu tun. Und wie kommst du auf Funktionen? Du meinst wahrscheinlich "transzendente Zahlen" https://www.matheretter.de/wiki/transzendente-zahlen Ich ziehe den Einwand gegen "transzendente Funktionen" zurück. Die Bezeichnung ist richtig. Si tacuisses... Wollte meinen Beitrag schon löschen, war aber zu spät. Betrachtet den ganzen Beitrag bitte als gelöscht. Ein alter Gaul hat sich vergaloppiert.
Es gibt hier ja viele Vorschläge, sich zu verzetteln. Dem TO würde es sicher schon reichen, seine Werte auf Integer zu skalieren (x 1000 zum Beispiel) und bei der anschließenden ltoa-Wandlung das Komma richtig einzufügen. Beispiel aus der Codesammlung: Beitrag "schnelle Wandlung long -> ASCII" und es gibt noch viele mehr. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|