Seite 1 von 3

Include - Dezimalzahlen (unlimitiert)

Verfasst: 04.03.2009 19:52
von STARGÅTE
Tachchen,

unter zuhilfenahme des Includes von Little John (Rechnen mit großen Zahlen als Strings) habe ich nun selber ein Include geschrieben welches das Rechnen mit unlimitiert Dezimalzahlen ermöglicht.

Dieses Include arbeitet jedoch (in den Rechnungen) nicht mit Strings sondern mit Longs, und ist damit beim Rechnen fast 10-100 mal schneller.

Hier gehts zur aktuellen version

Verfasst: 04.03.2009 23:47
von Little John
Cool! :allright:
Das Include ist noch etwas "durcheinander" und unfertig, aber mich interessiert ob es gebracuht wird (da ja immer wieder Leute kommen die genauer rechnen wollen) und ob irgendwelche BUGs gefunden werden.
Ich hoffe, ich werde morgen nachmittag/abend etwas Zeit haben um Deine Funktionen zu testen.

Gruß, Little John

Verfasst: 05.03.2009 00:36
von hjbremer
sehr interressant und ganz sicher brauchbar, erinnert mich an eine alte BCD LIB für QB. Habe mir den Link auf diese Seite sofort abgespeichert.

:allright: :allright: :allright:

Re: Include - Dezimalzahlen (unlimitiert)

Verfasst: 05.03.2009 08:08
von DrShrek
STARGÅTE hat geschrieben: ..., aber mich interessiert ob es gebracuht wird (da ja immer wieder Leute kommen die genauer rechnen wollen) und ob irgendwelche BUGs gefunden werden.
Sollte jeden Lib Schreiber klar sein:
So eine Lib kann immer mal gebraucht werden...
´...nur im Moment brauche ich und sicher auch andere es nicht...
...das heisst aber nicht das es deswegen nicht weiterentwickelt werden sollte.

(Siehe nur Beispiel: XOr, OpenGL OOP Lib).

Also dranbleiben...auch wenn die Resonanz nicht immer einen Aufschrei der Lust erzeugt ;-)

PS.: Nachfragen dieser Art führen zu keinen aussagekräftigen Meinungsbild.

Verfasst: 05.03.2009 18:30
von Little John
Hallo STARGÅTE,

ich habe mal etwas Code geschrieben, um die Ergebnisse Deiner und meiner Funktionen miteinander zu vergleichen. Er ist recht einfach gehalten und verwendet nur ganze Zahlen, da mein Code nur diese unterstützt. Ich hoffe, ich habe Deine Funktionen korrekt eingebunden. Es finden sich viele widersprüchliche Ergebnisse, und oft erhalte ich einen IMA in Deiner Prozedur DivDec().

Gruß, Little John

Code: Alles auswählen

; Vergleich zweier Funktionssammlungen zum Rechnen mit fast beliebig großen Zahlen
; PB 4.30

XIncludeFile "BigMath.pbi"  ; Little John
XIncludeFile "Dec.pbi"      ; STARGATE


Macro RandomRange (_lo_, _hi_)
   ; random integer between lo and hi, inclusive
   _lo_ + Random(_hi_-_lo_)
EndMacro

Procedure.s BigRandom (minDigits, maxDigits)
   ; in : minDigits: Mindestanzahl Stellen
   ;      maxDigits: Höchstanzahl  Stellen
   ; out: den Parametern entsprechende positive Zufallszahl als String
   Protected numDigits, i
   Protected ret.s

   numDigits = RandomRange(minDigits, maxDigits)
   ret = ""
   For i = 1 To numDigits
      ret + Str(RandomRange(0,9))
   Next
   ProcedureReturn ret
EndProcedure


#NumTests = 20
#MinDigits = 100
#MaxDigits = 200

Define *a, *b, i, dot
Define a.s, b.s, result1.s, result2.s

For i = 1 To #NumTests
   a = BigRandom(#MinDigits, #MaxDigits)
   b = BigRandom(#MinDigits, #MaxDigits)
   *a = SetDec(a)
   *b = SetDec(b)

   If BigCmp(a,b) <> CmpDec(*a,*b)
      Debug "Keine Übereinstimmung bei Vergleich von"
      Debug a + " und"
      Debug b
      Debug ""
   EndIf

   result1 = BigAdd(a,b)
   result2 = GetDec(AddDec(*a,*b))
   If result1 <> result2
      Debug "Keine Übereinstimmung bei Addition von"
      Debug a + " und"
      Debug b
      Debug ""
   EndIf

   result1 = BigSub(a,b)
   result2 = GetDec(SubDec(*a,*b))
   If result1 <> result2
      Debug "Keine Übereinstimmung bei Subtraktion von"
      Debug a + " und"
      Debug b
      Debug ""
   EndIf

   result1 = BigMul(a,b)
   result2 = GetDec(MulDec(*a,*b))
   If result1 <> result2
      Debug "Keine Übereinstimmung bei Multiplikation von"
      Debug a + " und"
      Debug b
      Debug ""
   EndIf

   If b <> "0"
      result1 = BigDiv(a,b)
      result2 = GetDec(DivDec(*a,*b))
      dot = FindString(result2, ".", 1)
      If dot
         result2 = Left(result2, dot-1)  ; ganzzahliger Anteil
      EndIf
      If result1 <> result2
         Debug "Keine Übereinstimmung bei Division von"
         Debug a + " und"
         Debug b
         Debug ""
      EndIf
   EndIf

   FreeDec(*a)
   FreeDec(*b)
Next

Debug "Fertig"

Verfasst: 05.03.2009 19:30
von STARGÅTE
:lol: jo es ist NIX gleich weil meine Zahlen IMMER ein Komma haben, acuh bei ganzen Zahlen : 100. statt bei dir 100
also einfach beim Vergleich noch ein "." bei deinen ergebnissen hinten dran ...

Beachtet man das kommt bei Add, Mul und Sub überall das gleiche raus ...

Bei Division gibs ein paar Probleme bei mir ... da gabe cih dir recht.
Liegt an :

Code: Alles auswählen

Shift - Log10(*Dec2\High\Value[*Dec2\HighFields-1])
Bei der seltsammerweise trotz prüfung mal n Log10(0) kommt und dann Shift "quark" wird und damit alles kaputt geht :roll:

Werde mich drum kümmern ...

EDIT: Auch bei Division kommt wenn es klappt das gleiche raus, halt nur manchmal diese IMAs

Verfasst: 05.03.2009 19:53
von Little John
STARGÅTE hat geschrieben::lol: jo es ist NIX gleich weil meine Zahlen IMMER ein Komma haben, acuh bei ganzen Zahlen : 100. statt bei dir 100
also einfach beim Vergleich noch ein "." bei deinen ergebnissen hinten dran ...
Na dann ... :lol:
Ich würde die Ergebnisse ohne . am Ende ausgeben, das entspricht nicht den üblichen Konventionen.

Gruß, Little John

Verfasst: 24.03.2009 20:53
von Little John
2STARGÅTE:
Hatte mich ja doch etwas gewurmt, dass Deine Routinen so viel schneller waren als meine. ;-) Daher habe ich meinen Code jetzt mal erheblich beschleunigt.
Deine Multiplikation ist aber weiterhin deutlich schneller, in dem Fall lohnt sich die "radikalere" ;-) Vorgehensweise sehr.

Gruß, Little John

Verfasst: 25.03.2009 01:43
von STARGÅTE
Jo, da bei der Multiplikation sehr oft "kleinzeug" Multipliziert wird und dann am ende noch mal addiert wird ...
aber du hast halt den Vorteil das du "fertige String" bekommst, ich dagegen nur Pointer die für die Zahl stehen ...

Re: Include - Dezimalzahlen (unlimitiert)

Verfasst: 15.12.2009 19:32
von STARGÅTE
Tachchen Leute,

in den letzten Wochen arbeite ich an eine komplett überarbeiteten Version meines Includes für Dezimalzahlen.

Viele Operationen konnte ich schon beschleunigen:
- Addieren - 15% schneller
- Multiplizieren - 15% schneller
- Dividieren - 50% schneller

Viele Operationen habe ich schon hinzugefügt:
- Potenzieren (nur mit ganzzahligen Exponenten)
- Radizieren (nur mit ganzzahligen Wurzelexponenten)
- Fakultät (nur ganze zahlen)
- ...

Auch speichere ich die Zahlen in einem andere Format ab, sodass allgemein Speicher gespart wird, und das Include auch für "rein ganze" Zahlen geeingnet ist.
Wichtig ist auch, das ich derzeitig den "Modus" drin habe das nach einer Operation die Zahlen dir daran beteiligt waren gelöscht werden, das soll vor Speicherüberauf schützen, aknn aber mit einem Flag unterdrückt werden falls man die Zahlen doch noch mal braucht.

Hier die Aktuelle Test-Version : Decimal.pbi
(Link aktuallisiert 9.7.2010)

Hinweis: Das ist nur eine Test-Version, Operationen wie Wurzelziehen laufen sehr instabil,
sie dient erst mal nur zum Testen und zur Bugsuche!

andere "krittische" Operationen wir Dividieren habe ich zwar inzwischen verbessert, trotzdem kann es bei Missbrauch zu Abstürzen kommen (IMA oder endlosschleifen)
Hinweis2: Diese Test-Version bitte vorerst nur mit Debugger starten, zwar sind die meisten Proceduren dann 5-10 mal langsammer aber dafür kann man es schneller beenden!

Hier mal ein paar kleine Beispiele:

Code: Alles auswählen

Debug "Fakultät von 1000"
Debug DecimalToString(FactorialDecimal(IntegerToDecimal(1000)))

Debug "1024 hoch 1024"
*Ergebnis = PowerDecimal(IntegerToDecimal(1024), IntegerToDecimal(1024))
Debug DecimalToString(*Ergebnis)

Debug "2.56^1000 durch 2.56^998"
*Zahl1 = PowerDecimal(StringToDecimal("2.56"), IntegerToDecimal(1000))
*Zahl2 = PowerDecimal(StringToDecimal("2.56"), IntegerToDecimal(998))
Debug DecimalToString(*Zahl1, #NoDecimal)
Debug DecimalToString(*Zahl2, #NoDecimal)
*Ergebnis2 = DivideDecimal(*Zahl1, *Zahl2, 10)
Debug DecimalToString(*Ergebnis2)

Debug "größten gemeinsammen Teiler von zwei großen Zahlen mit Dezimalstellen"
*Zahl1 = StringToDecimal("140032456034604564060345063546.25")
*Zahl2 = StringToDecimal("74356367865484675647864667768.75")
*Ergebnis3 = GCDDecimal(*Zahl1, *Zahl2)
Debug DecimalToString(*Ergebnis3)
Obwohl die Funktion Power zwar auch riesige Zahlen erlaubt, ist es nicht ratsam diese auch zu benutzen.
Kleine Beispielrechnung:
eine Milliarde hoch eine Milliarde
wäre eine 1 mit 9 Milliarde Nullen diese Zahl rechnet das Programm zwar schnell aus aber darf nicht mehr als String dargestellt werden ! weil 9 Milliarden Nullen ca 9 GIGABYTE ! verschligen würden.
Als Dezimal Zahl in meinem Include sind es aber nur wenige Byte, da die Zahl nur wenige echte stellen hat , dafür eine riesige Potenz, dafür gibs DebugDecimal()

Code: Alles auswählen

Debug "1000000000 hoch 1000000000"
*Ergebnis = PowerDecimal(IntegerToDecimal(1000000000), IntegerToDecimal(1000000000))
Debug DebugDecimal(*Ergebnis)
Würde man jetzt aber eine beliebige Zahl so hoch Potenzieren würde das sehr lange dauern! daher nicht ratsam!

Genausowenig sollte man sich von 1/7 "alle" Dezimalstellen ausgeben lassen, denn DivideDecimal bricht erst ab wenn die angegebene Prezision erreicht ist oder kein rest mehr da ist.

Was ich noch einbauen möchte ist, das die Division selber eine Periode erkennt:
1/7 = 0.142857
1/6 = 0.16
Machbar wäre das! indem ich abbrechen wenn ein Rest schon mal vorher Rest war.
Jedoch müsste ich dann alle Operationen (Plus, Mal) auch damit vertraut machen mit Perionen zu rechnen.
1.6 + 1.3 = 3
So genau der Wort, testet mal ein Bisschen "vorsichtig" rum und meldet mir Bugs und nennt auch Wünsche.
Sowas wie nächte Primzahl nach 10^100 ist in Arbeit