Nullen von float Wert ermitteln

#7397057
Lesenswert?

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?

Gast #7397068
Lesenswert?

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

#7397071
Lesenswert?

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.

#7397075
Lesenswert?

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
}
Moderator (Firma: Titel) Persönliche Seite #7397090
Lesenswert?

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?

Moderator (Firma: Titel) Persönliche Seite #7397196
Lesenswert?

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.

Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #7397199
Lesenswert?

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.

Angehängte Dateien:
#7397278
Lesenswert?

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.

#7397282
Lesenswert?

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
}
Moderator Persönliche Seite #7397298
Lesenswert?

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.

#7397312
Lesenswert?

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.

#7397343
Lesenswert?

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.

#7397390
Lesenswert?

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.

Moderator (Firma: Titel) Persönliche Seite #7397409
Lesenswert?

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.

Gast #7397411
Lesenswert?

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 ...

Moderator (Firma: Titel) Persönliche Seite #7397422
Lesenswert?

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...

#7397475
Lesenswert?

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"

#7397529
Lesenswert?

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.

#7397738
Lesenswert?

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.

#7397755
Lesenswert?

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.

#7397776
Lesenswert?

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.

#7397794
Lesenswert?

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.

#7397821
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren