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?
:
Bearbeitet durch User
Die Zahl in einen String umwandeln (Funktion dtostrf()) und die Nullen zählen.
He S. schrieb: > Wie kann ich die Anzahl der Nullen berechnen? 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.
He S. schrieb: > Wie kann ich die Anzahl der Nullen berechnen? Ja... Soweit mir bekannt, nennt sich das notwendige Verfahren: Zählen!
He S. schrieb: > Ich möchte zum Beispiel von einem float Wert 0.01 die Nullen ermitteln. > Wie kann ich die Anzahl der Nullen berechnen? Justin S. schrieb: > zahl = 0.01; > anzahlDerNullen = ceil( -log10( zahl ) ); 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.
:
Bearbeitet durch User
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.
He S. schrieb: > Ok ich hab mich nicht richtig ausgedrückt. > > Beispiel: 0.001 > > Ich möchte die Zahlen vor der 1 ermitteln. 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):
1 | int fuehrende_0=0; |
2 | while (zahl_float < 1.0f) |
3 | {
|
4 | zahl_float = zahl_float*10; |
5 | fuehrende_0++; |
6 | }
|
He S. schrieb: > Ok ich hab mich nicht richtig ausgedrückt. > > Beispiel: 0.001 > > Ich möchte die Zahlen vor der 1 ermitteln. Na dann musst du hinten anfangen und alle Nullen zählen, bis du entweder das Zeichen '.' oder den Stringanfang findest.
Mi N. schrieb: > Robert G. schrieb: >> Also irgendwie so (ungetestet): > > Teste mal mit -1.0 ;-) Guter Einwand. sollte sich aber mit abs() lösen lassen.
He S. schrieb: > Beispiel: 0.001 > Ich möchte die Zahlen vor der 1 ermitteln. 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? Robert G. schrieb: > Du könntest die Zahl so oft mit 10 multiplizieren, und dann auf >1 > prüfen. 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?
:
Bearbeitet durch Moderator
Eine Floatzahl ist sowieso intern auf 1.xxxx exp xx normiert, und das shiften macht der Exponent. Also muss man nur den exponent auswerten
:
Bearbeitet durch User
Purzel H. schrieb: > 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.
Purzel H. schrieb: > Eine Floatzahl ist sowieso intern auf 1.xxxx exp xx normiert, und das > shiften macht der Exponent. Also muss man nur den exponent auswerten 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.
:
Bearbeitet durch Moderator
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. - https://zogg-jm.ch/IEEE_754_Umwandlung_32_bit_Hexadezimal_zu_Gleitkomma.html
:
Bearbeitet durch Moderator
Lothar M. schrieb: > Aber wie auch immer: eine 0,001 kann binär nicht exakt dargestellt > werden. Die Lösung hatte Falk B. doch schon ober genannt: > Die Zahl in einen String umwandeln (Funktion dtostrf()) und die Nullen > zählen. Einfach konsistent überall die gleiche Routine zur Umwandlung in die Dezimaldarstellung benutzen.
Xanthippos schrieb: > Die Lösung hatte Falk B. doch schon ober genannt Schon, aber es kam aber eben auch noch ein augenscheinlich "einfacher" aber im Detail tückischer Vorschlag danach.
Xanthippos schrieb: > Die Lösung hatte Falk B. doch schon ober genannt: 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.
Justin S. schrieb: > zahl = 0.01; > anzahlDerNullen = ceil( -log10( zahl ) ); Mir gefällt die Lösung von Justin S. (derwer). Python3:
1 | >>> import math |
2 | >>> zahl=0.001 |
3 | >>> anzahlDerNullen = math.ceil(-math.log10(zahl)) |
4 | >>> print (anzahlDerNullen) |
5 | 3
|
Oder in C:
1 | #include <stdio.h> |
2 | #include <math.h> |
3 | int main() |
4 | {
|
5 | double zahl=0.001; |
6 | printf("%d\n",(int)ceil(-log10(zahl))); |
7 | return 0; |
8 | }
|
:
Bearbeitet durch User
He S. schrieb: > Ich möchte zum Beispiel von einem float Wert 0.01 die Nullen ermitteln. 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". Christoph K. schrieb: > printf("%d\n",(int)ceil(-log10(zahl))); 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.
He S. schrieb: > Ok ich hab mich nicht richtig ausgedrückt. > Beispiel: 0.001 > Ich möchte die Zahlen vor der 1 ermitteln. 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.
Lothar M. schrieb: > Schon, aber es kam aber eben auch noch ein augenscheinlich "einfacher" > aber im Detail tückischer Vorschlag danach. 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.: > Der Funktion soll auf einem 32bit Mikrocontroller eingesetzt werden. > Programmiersprache C. Frank M.: > Der TO hat leider nicht verraten, ob die "Ermittlung" auf einem > ATTiny13 oder Großrechner erfolgen soll.
:
Bearbeitet durch User
Frank M. schrieb: > He S. schrieb: >> Ich möchte zum Beispiel von einem float Wert 0.01 die Nullen ermitteln. > > 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". > > Christoph K. schrieb: >> printf("%d\n",(int)ceil(-log10(zahl))); > > 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. 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.
Christoph K. schrieb: > Mir gefällt die Lösung von Justin S. (derwer). > > anzahlDerNullen = math.ceil(-math.log10(zahl)) > print (anzahlDerNullen) > > printf("%d\n",(int)ceil(-log10(zahl))); 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.
:
Bearbeitet durch User
Rainer W. schrieb: > und es also reicht, wenn du direkt den Exponenten auswertest. 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.
:
Bearbeitet durch Moderator
Frank M. schrieb: > 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. He S. schrieb: > Der Funktion soll auf einem 32bit Mikrocontroller eingesetzt werden. > Programmiersprache C. 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 ...
Justin S. schrieb: > Und Wandlung in einen String ist ebenfalls "heftige Kost" 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
1 | printf("Die Zahl %f enthält %d Nullen", f, n); |
dann bleibt einem nichts andere übrig, als genau die Nullen in genau diesem String zu zählen...
:
Bearbeitet durch Moderator
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. Beitrag "Hilfestellung LCD Display"
Harald K. schrieb: > 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. > > Beitrag "Hilfestellung LCD Display" 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.
:
Bearbeitet durch User
Michael B. schrieb: > Christoph K. schrieb: >> Mir gefällt die Lösung von Justin S. (derwer). >> >> anzahlDerNullen = math.ceil(-math.log10(zahl)) >> print (anzahlDerNullen) >> >> printf("%d\n",(int)ceil(-log10(zahl))); > > Funktioniert halt nicht. > > Dank float ist das Ergebnis nicht korrekt, log10(10000.0) liefert nicht > unbedingt 4 sondern gerne mal 3.999999987 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.
Christoph K. schrieb: > Ja, und wenn schon. Erstens ist es nicht float sondern double, zweitens > macht ceil() in jedem Fall eine 4 draus. 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.
Michael B. schrieb: > 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. Eben! Deshalb runden Ausgaberoutinen auch kaufmännisch. Ein halber Stellenwert wird vorm Abrunden aufaddiert (z. B. + 0.005 für %.2f) bzw. vorzeichengemäß subtrahiert.
Michael B. schrieb: > Christoph K. schrieb: >> Ja, und wenn schon. Erstens ist es nicht float sondern double, zweitens >> macht ceil() in jedem Fall eine 4 draus. > > Es war der feine Hinweis, das ceil() hier wohl falsch ist und floor() > lauten sollte. > Die 4 bezog sich auf das von Dir gegebene Beispiel. (10000.) > 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. > 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.
1 | #include <stdio.h> |
2 | #include <math.h> |
3 | int main() |
4 | {
|
5 | double zahl=10000.; |
6 | printf("%d %lf\n",(int)ceil(-log10(zahl)),ceil(-log10(zahl))); |
7 | printf("%d %lf\n",(int)floor(-log10(zahl)),floor(-log10(zahl))); |
8 | zahl=0.001; |
9 | printf("%d %lf\n",(int)ceil(-log10(zahl)),ceil(-log10(zahl))); |
10 | printf("%d %lf\n",(int)floor(-log10(zahl)),floor(-log10(zahl))); |
11 | return 0; |
12 | }
|
> 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. Schön, daß man auf diese Weise jung bleiben kann. Ich glaube, ich habe mehr Jahre C (seit 1979) auf dem Buckel als Du.
:
Bearbeitet durch User
Christoph K. schrieb: > transzendentale Funktionen, heißt es. 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.
:
Bearbeitet durch User
Harald K. schrieb: > Der Verdacht besteht, daß es um die Ausgabe eines Float-Wertes auf einem > LC-Display geht, bei dem führende Nullen unterbunden werden sollen. 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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.