![]() |
runden von 0.0099999997765
ich hatte immer das Problem, dass ich eine Zahl runden wollte, aber ihre anzahl der Nachkommastellen nicht kannte.
somit sahen die Floattostr() Ausgaben immer etwas nebulös aus, oder aber die Zahl war zu stark gerundet. Ich hab hier mal eine Funktion gebastelt. Könntet ihr diese mal auf Herz und Nieren prüfen bitte ? Ich bin mir nicht sicher, ob ich ein Detail übersehen haben könnte. Vielleicht fällt ja jemanden noch etwas ein um die Geschwindigkeit zu optimieren. Wäre vielleicht etwas für die Codelib. Man erhält für: 115,859997410327 - 115,86 100,99 - 100,99 100 - 100 101 - 101 109 - 109 100,4 - 100,4 100 - 100 126,61999511719 - 126,62 0,0099999997765 - 0,01 115,089999999776 - 115,09 99,99999997765 - 100 99,99999997765 - 100 0,99999997765 - 1 99,09999997765 - 99,1 99,0199999997765 - 99,02 99,0100001245678 - 99,01 115,860000610352 - 115,86 115,859997410327 - 115,86 115,859974103278 - 115,86 115,85074103278 - 115,85074103278 0,00999999977648258 - 0,01 115,790000915527 - 115,79 Ausgabe mit:
Delphi-Quellcode:
d := 126.61999511719;
testmemo.Lines.Add(floattostr(d) + ' - ' + floattostr(xRound(d)));
Delphi-Quellcode:
/==============================================================================
// function xRound // rundet und findet selbständig die Anzahl der Nachkommastellen //============================================================================== Function xRound (aValue : Extended) : extended; Const cMaxDigits = 12; cCount = 2; // anzahl des auftretens von Ziffer 9 oder 0 (z.B. 99 oder 00) var Count9 : Integer; // der count von 99 oder 00 hintereinander Count0 : Integer; Check9 : Boolean; // 99 war da check0 : boolean; // 00 war da Zahl : Int64; Ziffer : Integer; NachkommaStellen : integer; Teiler : Extended; Begin Count9 := 0; count0 := 0; check0 := false; check9 := false; Nachkommastellen := cMaxDigits; Zahl := round(Power(10,cMaxDigits) * Frac (aValue)); /// 0.0099999997765 => 99999997765 While (Zahl>0) do begin Ziffer := Zahl mod 10; if Ziffer = 0 then inc(Count0) else if Ziffer = 9 then inc(Count9) else begin count0 := 0; count9 := 0; end; // else if not check9 and (count0 >= cCount) then check0 := true; // nicht auf check0 stellen, wenn schon check9 if not check0 and (count9 >= cCount) then check9 := true; if check9 then if (Ziffer <> 9) then break; if check0 then if (Ziffer <> 0) then break; Zahl := Zahl div 10; // von hinten abschneiden dec(Nachkommastellen); end; // While Zahl > = if not (check0 or check9) then nachkommastellen := cMaxDigits; Teiler := power(10, Nachkommastellen); result := round(aValue * Teiler) / Teiler; End; // xRound //============================================================================== |
Re: runden von 0.0099999997765
Zitat:
|
Re: runden von 0.0099999997765
Zitat:
|
Re: runden von 0.0099999997765
Naja, ich verstehe nicht so ganz, warum du etwas selber basteln willst, was es bereits schon gibt.
Wenn ich mir deine Beispiele so anschaue (bis auf 115,85074103278 - 115,85074103278 da sehe ich irgendwie die Logik nicht drin), ist das identich mit RoundTo(aValue, -2). |
Re: runden von 0.0099999997765
Zitat:
RoundTo kann ich nicht nehmen, da ich ja die 2 gar nicht kenne, sondern nur die Zahl ansich habe. Ist auch nicht vorwiegend für Formatierungen gedacht, sondern zum rechnen mit Floatzahlen. Ausserdem kannst Du mit RoundTo nicht auf 0,5 runden (brauch ich aber) 5000 5000,5 5001 5001,5 |
Re: runden von 0.0099999997765
Achso, jetzt verstehe ich auch das Problem erst :oops:
Du willst also nicht, dass 00 oder 99 hinterm Komma vorkommt bzw. wenn es vorkommt soll an dieser Stelle gerundet werden... |
Re: runden von 0.0099999997765
Erstmal eins vorneweg: Gute Funktion, stoxx!
Aber: Ich weiss nicht, wozu ich das gebrauchen könnte. Im wirklichen Leben verwendet man eigentlich ausschließlich feste Nachkommastellen bzw. feste Stellen. Wenn ich z.B. Messreihen darstelle, werde ich wohl kaum 123.4353513131345 V anzeigen. Weil das einfach falsch ist, selbst wenn der Voltometer diesen Wert zurück liefert. Tatsache ist aber, das das Messgerät z.B. nur auf +/- 0.01% genau messen kann. Das ergibt 5 Stellen. Eine Spannung von 100-999 Volt kann ich also mit 2 Nachkommastellen angeben... Kurzum: Im physikalischen Bereich wird i.A. mit einer festen Stellenanzahl gearbeitet. In der Mathematik arbeitet man mit der Exponentialschreibweise, also z.B. 1,234 E+05, mit anderen Worten, auch eine feste Stellenanzahl, nur die Darstellung unterscheidet sich. In visuellen Bereich wird man dagegen eine Darstellung mit festen Dezimalstellen vorziehen, also z.B. 123,400 Aus gutem Grund überlässt man es dem Programmierer, eine *sinnvolle* Darstellung zu verwenden. Ein wirklich realitätsnahes Praxisbeispiel ist die Anzeige bei irgendwelchen Web-Umfragen. Wenn z.B. 13 Leute teilgenommen haben, und 6 haben sich für blau entschieden, dann steht dort häufig blau: 46,153%. Diese Darstellung impliziert jedoch, das mindestens 100000 Personen teilgenommen haben, denn es sind ja 46,153 und nicht 46,154 %. Eine Funktion, die mir eine Zahl so rundet, das es 'irgendwie ansprechend' aussieht, ist eine lustige (und gut gemachte!) Angelegenheit, birgt aber das echte Risiko, das der Dilettantismus noch weiter um sich greift. Eine Funktion, die eine Zahl mit einer beliebigen Granularität rundet, wäre z.B.:
Delphi-Quellcode:
Die Funktion sorgt nur dafür, das die Zahl ohne Rest durch die Granularität teilbar ist.
Function GranularityRound (aNumber, aGranularity : Extended) : Extended;
Begin Result := Trunc (aNumber / aGranularity + 0.5) * aGranularity; End; // granularityRound (1.2343434, 0.02) = 1.24 // granularityRound (1.2343434, 0.1 ) = 1.2 // granularityRound (123.43434, 5 ) = 125 Ich will die Leistung von stoxx wirklich nicht schmälern, sondern nur meinen vergreisten Zeigefinger heben, und darauf hindeuten, wie wichtig eine *sinnvolle* Darstellung ist. Genug gelabert, danke für die Aufmerksamkeit. :cheers: |
Re: runden von 0.0099999997765
Zitat:
Hi ! na vielleicht bin ich auch der einzigste Mensch auf Erden, der diese Funktion benötigt ;-) Kann durchaus sein. Im Wertpapierbereich haben Aktien gewöhnlich 2 Nachkommastellen, Futures und andere Produkte haben je nachdem auch 4 oder 6 Nachkommastellen. und es gibt minimale Preisbewegungen in 0,25er oder in 0,5er oder in ganzen Schritten oder wie auch immer. Ich arbeite mit einer API an eine Brokersofware. Diese liefert auch die minimale Schrittweite, arbeitet aber dummerweise mit Single Werten. Da werden aber dummerweise Zahlen von 0.009999999765 übermittelt für 0,01. Diese 0,01 brauch ich aber um (ausgerechnete) Preise korrekt zu runden. Fall b) bei berechnungen mit Gleitkommazahlen treten selbst bei einfachen additionen sehr schnell unerwünschte Fehler auf, die sich äußerst schnell fortpflanzen. Nach einigen Berechnungsschritten runde ich die Werte. Gut wenn man weiß, mit wievielen Nachkommastellen man das tun soll :-) |
Re: runden von 0.0099999997765
Hi stoxx. Verwende statt Single lieber Currency oder Extended-Werte. Am besten wäre BCD. Das Problem ist, das sich i.a. Dezimalbrüche nicht genau durch das Floatingpoint-Format darstellen lassen. Daher gibt es Schutzstellen, d.h. Du nimmst billigend die Rundungsfehler in Kauf (bitte nicht mit Single). Wenn Du nur addierst oder substrahierst, dann werden diese Fehler im Bereich von maximal 10^-8 bleiben, also weit jenseits der von Dir gewünschtne Genaugigkeit von 10^-4. Insofern sollte es reichen, die Darstellung auf feste Nachkommastellen zu runden. Versuch doch mal meine Funktion, ich glaub sogar,es gibt sowas schon in der Math-Unit.
Wie gesagt, Deine Funktion hat mir gefallen. Vielleicht wird sie mal von 2 Personen verwendet: Nämlich auch von mir. :mrgreen: |
Re: runden von 0.0099999997765
Zitat:
ich hab mir mal ein paar Gedanken dazu gemacht, und das Resultat ist weiter unten. Um die vielen Divs und Mods zu vermeiden, hab ich das ganze in Assembler geschrieben. Die Suche nach doppelten Nullen / Neunen lasse ich in den 128 Bit breiten XMM-Registern erledigen - ohne Schleifen, ifs und thens.... Soweit ich weiß unterstützt AMD die verwendeten Befehle auch. Bei den von Dir aufgeführten Beispielen bringt meine Funktion identische Resultate. Die Funktion, ich habe sie (in Anlehnung an XRound) YRound genannt, hat die Parameter v:extended - entspricht Deinem avalue mindigs:integer - soviel Stellen nach dem Dezimalpunkt bleiben mindestens maxdigs:integer - soviel Stellen nach dem Dezimalpunkt bleiben höchstens fromleft:boolean - wenn True, dann wird die Suche nach doppelten Nullen / Neunen von links nach rechts durchgeführt, sonst, wie bei Dir, von rechts nach links. Anders als Deine Version arbeitet sie auch mit negativen Zahlen. mindigs und maxdigs müssen im Bereich 0..18 liegen, was nicht geprüft wird, ggfs. also in einer Exception endet.
Delphi-Quellcode:
FUNCTION YRound(v:extended; mindigs,maxdigs:integer; fromleft:boolean=false):extended;
const e18:int64=1000000000000000000; p10:array[0..18] of int64= (1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000, 10000000000,100000000000,1000000000000,10000000000000,100000000000000, 1000000000000000,10000000000000000,100000000000000000, 1000000000000000000); nine:array[0..1] of int64= ($9999999999999999,$9999999999999999); mask:array[0..19] of integer= ($000,$000,$100,$100,$180,$180,$1C0,$1C0,$1E0,$1E0, $1F0,$1F0,$1F8,$1F8,$1FC,$1FC,$1FE,$1FE,$1FF,$1FF); asm // --> Stack = V // --> EAX = mindigs // --> EDX = maxdigs // --> ECX = fromleft // <-- Gerundetes V //---------------------------------------------------------------------- jmp @Entry // Subroutine zum Ermitteln der Nachkommastellen @GetDigs: // BCD-Zahl in XMM0 und XMM1 movdqu xmm0,[esp+4] // +4 wegen Returnadresse movdqa xmm1,xmm0 // Bytes mit '00' vergleichen und Digits ermitteln pcmpeqb xmm0,xmm2 pmovmskb ebx,xmm0 // Ergebnisse in EBX call @GetDigs1 // Bytes mit '99' vergleichen und Digits ermitteln pcmpeqb xmm1,xmm3 pmovmskb ebx,xmm1 // Ergebnisse in EBX @GetDigs1: and ebx,edi // nur gültige Bits zulassen or ecx,ecx // fromleft js @GetDigs2 // ja bsf ebx,ebx // niedrigstes 1 Bit in EBX jnz @GetDigs3 ret @GetDigs2: bsr ebx,ebx // höchstes 1 Bit in EBX jz @GetDigs4 // alle 0 @GetDigs3: sub ebx,8 neg ebx add ebx,ebx // =Nachkommastellen add bx,cx // +1 wenn aus verschobener BCD cmp ebx,edx // weniger als bisher ? jae @GetDigs4 // nein mov edx,ebx // kleineren Wert merken @GetDigs4: ret //---------------------------------------------------------------------- // Register retten @Entry: push ebx push edi push esi // 16 Bytes auf Stack reservieren sub esp,16 // Nachkommateil als BCD-Zahl an [ESP] speichern fld v // st0=v fabs // st0=Abs(v); fld st(0) // st1=st0=v fld st(0) // st2=s1=st0=v fnstcw word [esp] // cw retten fnstcw word [esp+2] fwait or word [esp],$0F00 // Richtung 0 runden fldcw word [esp] frndint // st2=st1=v, st0=Trunc(v) fwait fldcw word [esp+2] // altes cw laden fsubp st(1),st(0) // st1=v, st0=Frac(v) fild e18 fmulp // st1=v, st0=Frac(v)*1e18 frndint // st1=v, st0=Round(Frac(v)*1e18) fbstp TByte [esp] // [ESP]=18stellige BCD-Zahl,st0=v // --------------------------------------------------------------- // An ESP steht jetzt Round(Frac(v)*1e18) als 18 stellige BCD-Zahl // In St(0) steht noch V für späteres Runden // --------------------------------------------------------------- // XMM2 mit Nullen und XMM2 mi Neunen füllen pxor xmm2,xmm2 movdqu xmm3,nine // Digits ermitteln auf Basis der BCD-Zahl ror ecx,1 // ECX Bit 0 in Bit 31 lea edi,mask mov esi,[edi+edx*4] // Bitmaske wenn verschobene Zahl geprüft wird mov edi,[edi+edx*4+4] // Bitmaske wenn BCD-Zahl geprüft wird call @GetDigs // BCD-Zahl um 1 Nibble nach oben verschieben mov ebx,[esp+4] shld [esp+8],ebx,4 mov ebx,[esp] shld [esp+4],ebx,4 shl [esp],4 // Digits ermitteln auf Basis der verschobenen BCD-Zahl mov edi,esi // Bitmaske für verschobene BCD-Zahl add ecx,1 call @GetDigs // Prüfen ob mindigs unterschritten, ggfs. korriggieren cmp edx,eax // Nachkommastellen < mindigits ? jae @1 // nein mov edx,eax // mindigits verwenden @1: // Und jetzt v runden auf EDX Nachkommastellen // Pascal : Teiler := power(10, Nachkommastellen); // result := round(aValue * Teiler) / Teiler; // v schlummert noch in st0 fild QWord [p10+edx*8] // st1=v, st0=10^EDX fmulp st(1),st(0) // st0=v*10^EDX frndint // st0=Round(v*10^EDX) fild QWord [p10+edx*8] // st1=Round(v*10^EDX), st0=10^EDX fdivp st(1),st(0) // st0=result=Round(v*10^EDX)/10^EDX bt Word [ebp+16],15 // war v negativ jnc @2 // nein fchs // st0=-st0 @2: // Stack freigeben add esp,16 // Register auf alten Stand bringen pop esi pop edi pop ebx end; Der Test der von Dir aufgeführten Beispiele bringt identische Ergebnisse, mal abgesehen von dem Zeitbedarf. Die vorletzte Spalte zeigt die CPU-Ticks für Deine Version, die letzte Spalte die Ticks für die obige Version.
Code:
Ich habe nicht ausführlich getestet - würde ich vor Verwendung dringend empfehlen.
CPU-Ticks
Zahl XRound YRound XRound YRound ---------------- ------ ------ ----- ------ 115.859997410327 115.86 115.86 7772 1096 100.99 100.99 100.99 7440 924 100 100 100 1392 1040 101 101 101 1396 916 109 109 109 1520 908 100.4 100.4 100.4 5588 916 100 100 100 1560 916 126.61999511719 126.62 126.62 7360 1064 0.0099999997765 0.01 0.01 4496 1036 115.089999999776 115.09 115.09 5692 1016 99.99999997765 100 100 6892 1012 99.99999997765 100 100 6536 1052 0.99999997765 1 1 6488 932 99.09999997765 99.1 99.1 5248 956 99.0199999997765 99.02 99.02 4160 920 99.0100001245678 99.01 99.01 3976 1008 115.860000610352 115.86 115.86 6516 920 115.859997410327 115.86 115.86 6424 964 115.859974103278 115.86 115.86 6148 984 115.85074103278 115.85074103278 115.85074103278 7056 1004 0.00999999977648 0.01 0.01 4500 1084 115.790000915527 115.79 115.79 6800 920 |
Re: runden von 0.0099999997765
Kurze Antwort, hochgradig inkompetent:
Die >2 Nachkommastellen lasse ich von Excel *mit Excel* runden. Alles Andere führt zu Reklamationen bei den Kunden. mfg |
Re: runden von 0.0099999997765
Zitat:
Du solltest doch keine Diplomarbeit draus machen :gruebel: Was soll ich da sagen, vielen Dank !!! Aber warum soll meine Funktion nicht mit negativen Zahlen arbeiten ? hab ich was übersehen, funktioniert doch ?! Dummweise reichen meine ASM Kenntnisse nicht aus, und ich kann die Funktion nur blind übernehmen. Testen ist da so eine Sache. Vielen Dank ! |
Re: runden von 0.0099999997765
Zitat:
Das Schlimme an manchen Menschen ist, daß sie so viele Dinge wissen, die so nicht sind. Vielleicht solltest Du Dir den ganzen Thread mal richtig durchlesen. Eventuell verstehst Du dann, warum Stoxx seine Rundungsfunktion geschrieben hat - und warum ich das Ganze etwas schneller gemacht habe. Mal nebenbei : Mit welchem Zahlenformat willst Du denn eine Rundung, wie Stoxx sie benötigt, erreichen ? |
Re: runden von 0.0099999997765
Hallo allerseits,
@Amateurprofi Du zitierst stoxx mit "Um nach einem Hin und Herwandeln ..." Ich kann das nirgendwo in diesem Thread finden, wo hast Du das her ? @stoxx Frage zu Deiner Broker API: Erhältst Du zu jedem Kurswert immer auch die minimale Schrittweite oder kannst Du die sonstwie zuverlässig bestimmen bevor Du mit den Kurswerten irgendwelche Berechnungen durchführst? Sind die Anzahl der Nachkommastellen bei allen Werten unbekannt, oder nur die der minimalen Schrittweiten? |
Re: runden von 0.0099999997765
Hallo Bit4bit, das hin und herwandeln bezog sich auf diesen Thread: (sind übrigens zwei ganz verschiedenen Anwendungsfälle)
![]() Zitat:
0,4999999878 steht dann drin. Aus der größe Zahl könnte man sicherlich bestimmen, dass eine Nachkommastelle sinnvoll wäre. Ich brauche aber genau die 0,5 um zum beispiel einen Wert von 5300,398978 auf 5300,5 runden zu können. Und eben nicht auf 5300,4 (was mit dem Wissen möglich gewesen wäre, dass man auf eine Nachkommastelle runden möchte) Wenn man dann einen Trade an die Börse schickt wird die Order mit einem Preis von 5300,4 abgewiesen- kein gültiger Preis. Somit brauchte ich eine Funktion, die mir aus 0,4999987 -> 0,5 herstellt. (wenn man mit 0,49999 anfängt zu runden ergibt das ganz unschöne Zahlen ;-) falls noch weiteres Interesse an der besagten API besteht ;-) ![]() |
Re: runden von 0.0099999997765
gelöscht
|
Re: runden von 0.0099999997765
Hi stoxx , hab noch zwei Fragen:
Ist die Anzahl der Nachkommastellen für jeden Kurswert bekannt? (Ich vermute mal : Ja) Welche Werte können denn überhaupt bei den minimalen Schrittweiten vorkommen, gibt es dort vielleicht eine Bildungsregel? Welche API benutzt Du denn, hab nix für Delphi gefunden ? |
Re: runden von 0.0099999997765
Hi Bit, was hast Du denn vor, dass Du so genau fragst ?
Zitat:
Zitat:
Zitat:
Üblicherweise würde man aber die völlig gleichwertige ActiveX Schnittstelle benutzen. Hast Du schonmal mit ActiveX gearbeitet ? Die API musst Du einfach als Typbibliothek importieren und danach steht Dir die API im Objectinspektor zur Verfügung. vlg stoxx |
Re: runden von 0.0099999997765
Liste der Anhänge anzeigen (Anzahl: 1)
Hi stoxx, ich hab nix vor, finde Dein Problem aber interessant!
Wenn man im Dezimalsystem abrunden will, teilt man einfach durch die entsprechende Zehnerpotenz und entfernt alle Nachkommastellen. Wenn man aufrunden will, addiert man vorher einen Wert von 9/10 der Zehnerpotenz. Das kaufmännische Runden unterscheidet sich hier nur dadurch, dass vor der Division nicht 9/10 sondern die Hälfte der Zehnerpotenz addiert wird. Möchte man für die Rundung jetzt Schrittweiten (S) wie 0,25 oder 0,5 verwenden, so formt man die zu rundende Zahl vor der Rundung durch eine Division durch S um, so dass wieder mit Schrittweiten von 10 gearbeitet werden kann. Dann rundet man wie oben beschrieben (Aufrunden, Abrunden oder kaufmännisch runden) und macht die Umformung durch die Multiplikation mit S wieder rückgängig. Kommen Werte aus der API, so können sie mit dieser Methode erst einmal "in Form" gebracht werden. Dabei ist es natürlich notwendig, dass die minimale Schrittweite bekannt ist. Für die Übergabe an die API müssen die Werte dann eventuell wieder durch 1.000.000 geteilt werden. Jetzt endlich zu Deinem ursprünglichen Problem: Ich denke mal, dass Du als minimale Schrittweite jeweils eine Zahl übergeben bekommst, die eigentlich nicht kleiner sein kann als 0,000001 und wohl nicht mehr als 4 signifikante Ziffern enthält, oder ? Die Darstellungsgenauigkeit einer Single müsste also eigentlich vollkommen ausreichend sein um diese Zahl darstellen zu können. Wenn eine solche Zahl in ihrer dezimalen Darstellung eine Reihe von Neunen enthält heißt das, dass die interne (binäre Darstellung) knapp unterhalb des tatsächlichen (korrekten) Wertes liegt. Entscheidend für die Korrektur dieser Zahl auf einen "vernünftigen" Wert ist folgende Überlegung: Die Stellen vor dem Komma benötigen zu ihrer binären Darstellung eine bestimmte Anzahl von Bits. Zahlen zwischen 64 und 127 belegen zum Beispiel alle 7 Bits, die Zahlen zwischen 128 und 255 benötigen 8 Bits usw. Diese Bits gehen für die Darstellung des Dezimalbruches verloren. Da eine Single Floating Point Variable in Delphi für die interne Darstellung der Mantisse 23 Bit benutzt, kann man sich die Anzahl der für den Binärbruch verfügbaren Bits jeweils ausrechnen. Nur Zahlen die kleiner als 8 sind können hier noch mit 6 Nachkommastellen dargestellt werden. Für 4 Nachkommastellen muss die Zahl kleiner als 512 sein. Zahlen kleiner als 65536 erlauben noch 2 Nachkommastellen. Man kann jetzt in Abhängigkeit der Größe einer Zahl entscheiden ob auf 2, 4 oder 6 Nachkomma-stellen aufgerundet werden muss. Dafür sind nur wenige Vergleiche notwendig. Alle anderen Werte, die Du durch die API übergeben bekommst, dürften dann also Kurswerte oder so was darstellen. Hier kennst Du ja die minimale Schrittweite und kannst die Werte wie oben beschrieben anpassen. Hab das ganze mal mit einigen Beispielen versehen und noch ausführlicher beschrieben als Anhang beigefügt. |
Re: runden von 0.0099999997765
Hallo bit4bit,
ich habe Deinen Beitrag erst jetzt irgendwie gelesen, Du hast Dir viele Gedanken darum gemacht. Zitat:
Wenn Du Dir den folgenden Beitrag anschaust: ![]() die Zahlen werden in 32 Bit in "meinem" speziellen Format abgespeichert ( in einem Integer) , bieten aber dennoch mehr Anzahl signifikanter Stellen, als ein Single Wert, weil ich für die Kodierung des "Exponenten" nicht 8 Bit wie bei einem Single Wert, sondern nur 2 Bit verwende. 0XX0 0000 0000 0000 0000 0000 0000 0011 in XX ( Bit 29 und Bit 30) werden die Nachkommstellen codiert. 4 Zustände sind mit 2 Bits möglich. ich benutze entweder 2, 4 oder 6 Nachkommastellen. Eine Zahl wie 0,5 * 10^-12 abzuspeichern ist dann natürlich nicht möglich, aber eben auch nicht nötig für meine Zwecke ! Zitat:
Was natürlich richtig ist, (weiß nicht, ob Du das gemeint hast) .. man könnte die minimale Preisdifferenz, wenn man sie erhält, zum Beispiel 0,249999999 selbst versuchen erstmal auf 0,25 zu runden (Anhand der Größe an sich dieser Zahl). Um dann damit wieder den eigentlichen Preis zu runden. Für alle Fälle wo ich aber wiederum nur die Zahl an sich kenne ( nicht die 0,25 ) macht sich das Verfahren sehr gut. warum machst Du das runden so kompliziert und addierst erst noch 9/10 ? round(wert / 0.25) * 0.25 bringt die mir gewünschten Ergebnisse. Gruß stoxx |
Re: runden von 0.0099999997765
Hi Stoxx,
hab leider jetzt erst Zeit gehabt! Zitat:
Beim Umwandeln in Double für die internen Berechnungen kriegst Du dann aber wieder Binärbrüche mit den entsprechenden Rundungsfehlern weil der Exponent beim Floating Point Format eben die Basis 2 hat und nicht die Basis 10 (bzw. 100) wie bei Deinem Spezialformat. Deswegen meine ich nach wie vor, dass es besser wäre, wenn du wenigstens bei allen internen Berechnungen nur ganze Zahlen benutzt, egal ob als Double oder als Int64. In Deiner Funktion SmallToDouble musst Du dafür einfach nur die Faktoren entsprechend ändern, ändert nix an der Laufzeit. Die kleinste darstellbare Einheit wäre dann eben ein 10.000stel Cent (entspricht 6 Dezimalstellen) und Du könntest alle weiteren Probleme mit Rundungsfehlern und Hin- und Zurückwandeln vergessen! Bei Multiplikationen bzw. Divisionen mußt du dann, wie schon früher gesagt, die Anzahl der gedachten Nachkommastellen "zu Fuß" nachhalten. Ist aber trivial. Die Int64 Darstellung hätte den Vorteil, dass alle Berechnungen sehr schnell gehen und außerdem sind die darstellbaren Beträge größer, weil ja der Platz für den Exponenten nicht benötigt wird. Zitat:
Zitat:
Wenn Du aber eine Floating Point Zahl hast, die Bruchteile (also Binärbrüche) enthält, ist mein Verfahren zur Korrektur genau so anwendbar! Für jede benutzte Mantissenlänge in Bit (Single, Real48, Double, Extended) gibt es eindeutige Grenzwerte für die jeweils möglichen dezimalen Nachkommastellen, nach dem schlichten Motto: "Je mehr Bits vor dem Komma stehen, um so weniger Bits stehen für den Binärbruch zur Verfügung". Dein Verfahren mit der Untersuchung eines Strings ist zwar sehr trickreich und wird auch mit der schnellen Assembler-Routine von Amateurprofi für Dich brauchbar sein, hat aber zwei Nachteile: 1. Das von mir dargestellte Verfahren zur Korrektur von Darstellungsfehlern auf Grund von Binärbrüchen mit endlicher Genauigkeit dürfte um einige Größenordnungen schneller sein, selbst wenn es nicht in Assembler kodiert wird. High speed Idee: Der Exponent der Floating Point Variablen (Bei Single = 8 Bit) kann als Index für einen Array mit der jeweiligen Anzahl von darstellbaren Nachkommastellen verwendet werden. 2. Ich fürchte, dass sich nicht beweisen lässt, dass Dein Verfahren in jedem Fall ein richtiges Ergebnis erzeugt, oder? Zitat:
wenn ich abrunden will addiere ich nix, und wenn ich kaufmännisch runden will addiere ich 5/10 ( Vulgo die Hälfte ) danach schneide ich die nicht benötigten Stellen ab ! Bei Integer geht das mit einem "div" Operator, simpler geht’s nicht. Bei Floating Point nimmst Du dann eben die Funktion Int() in Verbindung mit dem "/" Operator Die Funktion Round rundet aber weder auf noch ab noch kaufmännisch, sondern macht ein Bankers Rounding, eine Abart des kaufmännischen Rundens. Wird für Dich auch in den meisten Fällen funktionieren .... aber: Wenn Du das hier mal aufmerksam liest ... ![]() ![]() ![]() ![]() ![]() ... verstehst Du bestimmt warum ich doch lieber die Kontrolle selbst behalte und reproduzierbare Ergebnisse der Benutzung der Round Funktion vorziehe. Wünsch' einen schönen Sonntag! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:25 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz