Include - Dezimalzahlen (unlimitiert)

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Include - Dezimalzahlen (unlimitiert)

Beitrag 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
Zuletzt geändert von STARGÅTE am 08.05.2010 19:20, insgesamt 4-mal geändert.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Little John

Beitrag 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
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Beitrag 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:
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
DrShrek
Beiträge: 1970
Registriert: 08.09.2004 00:59

Re: Include - Dezimalzahlen (unlimitiert)

Beitrag 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.
Siehste! Geht doch....?!
PB*, *4PB, PetriDish, Movie2Image, PictureManager, TrainYourBrain, ...
Little John

Beitrag 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"
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Beitrag 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
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Little John

Beitrag 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
Little John

Beitrag 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
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Beitrag 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 ...
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Include - Dezimalzahlen (unlimitiert)

Beitrag 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
Zuletzt geändert von STARGÅTE am 09.07.2010 15:58, insgesamt 2-mal geändert.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Antworten