Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Sum() - Unbegrenzt lange Ganzzahlen addieren


  • Please log in to reply
19 replies to this topic
Alibaba
  • Members
  • 435 posts
  • Last active: Nov 19 2014 04:21 PM
  • Joined: 01 Nov 2012

Diese Funktion habe ich geschrieben, da es letztens im IRC die Diskussion gab, wie man mit reinem AHK (und ohne Verwendung von Zusätlichen Funktionen oder BigInteger) diverse Potenzen von 2 berechnen kann.

 

Das Geheimnis ist, dass die Funktion nicht mit 2 Zahlen rechnet, sondern mit 2 Strings, welche Zahlen enthalten. Genauer gesagt verfährt die Funktion genau so, wie es jeder von uns in der Grundschule gelernt hat. Sie addiert die einzelnen Stellen von hinten nach vorne und bildet falls nötig jeweils den Übertrag.

Somit können die Zahlen beliebig viele Stellen besitzen und sind nicht auf den 64bit Integer Bereich von -9223372036854775807 bis 9223372036854775807 begrenzt.

Sum(v1, v2)
{
	r := "", b := 0, lhz := ""
	Loop % Abs(StrLen(v1) - StrLen(v2))
		lhz .= 0
	v1 := Flip((StrLen(v1) < StrLen(v2)) ? lhz . v1 : v1), v2 := Flip((StrLen(v2) < StrLen(v1)) ? lhz . v2 : v2)
	Loop, Parse, v1
	{
		d := A_LoopField + SubStr(v2, A_Index, 1) + b
		If (d > 9) {
			b := SubStr(d, 1, 1)
			d := SubStr(d, 2, 1)
		} else
			b := 0
		r := d . r
	}
	if (b > 0)
		r := b . r
	return r
}

Flip(in) {
    VarSetCapacity(out, n:=StrLen(in))
    Loop %n%
        out .= SubStr(in, n--, 1)
    return out
}

Damit kann man jetzt beispielsweise 2 hoch 1000 exakt berechnen, eine Zahl mit 302 Dezimalstellen, mit welcher Autohotkey im Normalfall nicht mehr umgehen könnte:

Loop 999
{
	var := Sum(var, var)
}
MsgBox % var
ExitApp

Das Ergebnis von 2**1000 ist:

10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140
43598457757469857480393456777482423098542107460506237114187795418215304647498358194126739876755916554394607706291457119647768654216766042
9831652624386837205668069376
(302 Dezimalstellen)

Das Ergebnis von 2**5000 ist:

Spoiler

 

Das Ergebnis von 2**10000 ist:

Spoiler

 

Die Ergebnisse habe ich mit Wolfram Alpha überprüft. Sie sind richtig. ;)


Find the recent autohotkey version here: ahkscript.org


nnnik
  • Members
  • 1625 posts
  • Last active: Jan 24 2019 02:19 PM
  • Joined: 28 Jul 2012

Nice.


Visit the new forum ahkscript.org.

http://ahkscript.org


nnnik
  • Members
  • 1625 posts
  • Last active: Jan 24 2019 02:19 PM
  • Joined: 28 Jul 2012

BTW du kannst doch mit MCode garantiert noch ein bischen speed rausholen oder?


Visit the new forum ahkscript.org.

http://ahkscript.org


Alibaba
  • Members
  • 435 posts
  • Last active: Nov 19 2014 04:21 PM
  • Joined: 01 Nov 2012

Auf jeden Fall. ;)

 

So ungefähr?

main := MCode("
(LTrim Join
2,x86:i0wkDIsBA0QkBANEJAiD+Ap9B8cBAAAAAMONUPaD+gl3CscBAQAAAIPA9sOD+BN+CscBAgAAAIPA7MMzwMM=,x64:RYsIR
APJRAPKQYP5Cn0LQccAAAAAAEGLwcNBjUH2g/gJdwxBxwABAAAAQY1B9sNBg/kTfgxBxwACAAAAQY1B7MMzwMM=
)")

SetBatchLines, -1
var := "2"

Loop 999
{
    var := Sum(var, var)
}
MsgBox % var
ExitApp

Sum(v1, v2)
{
    global main
    r := "", b := 0, lhz := ""
    Loop % Abs(StrLen(v1) - StrLen(v2))
        lhz .= 0
    v1 := Flip((StrLen(v1) < StrLen(v2)) ? lhz . v1 : v1), v2 := Flip((StrLen(v2) < StrLen(v1)) ? lhz . v2 : v2)
    Loop, Parse, v1
        r := DllCall(main, "UINT", A_LoopField, "UINT", SubStr(v2, A_Index, 1), "UINT*", b, "cdecl") . r
    return ((b > 0) ? b : "") . r
}

Flip(in) {
    VarSetCapacity(out, n:=StrLen(in))
    Loop %n%
        out .= SubStr(in, n--, 1)
    return out
}

MCode(mcode)
{
  static e := {1:4, 2:1}, c := (A_PtrSize=8) ? "x64" : "x86"
  if (!regexmatch(mcode, "^([0-9]+),(" c ":|.*?," c ":)([^,]+)", m))
    return
  if (!DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", 0, "uint*", s, "ptr", 0, "ptr", 0))
    return
  p := DllCall("GlobalAlloc", "uint", 0, "ptr", s, "ptr")
  if (c="x64")
    DllCall("VirtualProtect", "ptr", p, "ptr", s, "uint", 0x40, "uint*", op)
  if (DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", p, "uint*", s, "ptr", 0, "ptr", 0))
    return p
  DllCall("GlobalFree", "ptr", p)
}

Find the recent autohotkey version here: ahkscript.org


nnnik
  • Members
  • 1625 posts
  • Last active: Jan 24 2019 02:19 PM
  • Joined: 28 Jul 2012

Code?

BTW ich meinte es eig. anders:

Input/ Output über Hex Sytem, immer 32 bit Werte verrechnen:

Einen Overflow von einem 32 bit unsigned int rechnest du so aus:

int Overflow (unsigned int a,unsigned int b){
If ((a&b)>((~a)&(~b)))
   return 1;
return 0
}

Visit the new forum ahkscript.org.

http://ahkscript.org


Alibaba
  • Members
  • 435 posts
  • Last active: Nov 19 2014 04:21 PM
  • Joined: 01 Nov 2012

Ich bin raus... confused.png


Find the recent autohotkey version here: ahkscript.org


Johnny R
  • Members
  • 54 posts
  • Last active: Sep 18 2015 05:36 AM
  • Joined: 03 Nov 2012

du kannst doch mit MCode garantiert noch ein bischen speed rausholen oder?

Was ist "MCode"?



nnnik
  • Members
  • 1625 posts
  • Last active: Jan 24 2019 02:19 PM
  • Joined: 28 Jul 2012

MCode ist dieser Teil:

main := MCode("
(LTrim Join
2,x86:i0wkDIsBA0QkBANEJAiD+Ap9B8cBAAAAAMONUPaD+gl3CscBAQAAAIPA9sOD+BN+CscBAgAAAIPA7MMzwMM=,x64:RYsIR
APJRAPKQYP5Cn0LQccAAAAAAEGLwcNBjUH2g/gJdwxBxwABAAAAQY1B9sNBg/kTfgxBxwACAAAAQY1B7MMzwMM=
)")

Es ist eine C++ o.ä. Funktion die Compiled wurde.

Dabei entsteht dann ein Code. Diesen Code kann man in Hex umwandeln und so in AHK Scripten benutzen.

Die Funktion ruft er übrigens so auf:

DllCall(main, "UINT", A_LoopField, "UINT", SubStr(v2, A_Index, 1), "UINT*", b, "cdecl") 

Visit the new forum ahkscript.org.

http://ahkscript.org


Johnny R
  • Members
  • 54 posts
  • Last active: Sep 18 2015 05:36 AM
  • Joined: 03 Nov 2012

Gibt es da irgendwo Näheres zu lesen, eine Einführung o. ä.?



nnnik
  • Members
  • 1625 posts
  • Last active: Jan 24 2019 02:19 PM
  • Joined: 28 Jul 2012

Nun ja wenn du Interesse hast:

http://www.cplusplus.com/doc/tutorial/

Erstmal musst du c++ einigermaßen verstehen.

Dann kannst du einfach den MCode mit einem Generator erstellen:

Hier findest du nähere Infos:

http://www.autohotke...or-x86-und-x64/


Visit the new forum ahkscript.org.

http://ahkscript.org


Alibaba
  • Members
  • 435 posts
  • Last active: Nov 19 2014 04:21 PM
  • Joined: 01 Nov 2012
Ach du meinst ich soll mir meine c++ Funktion als HEX Code generieren lassen?

Find the recent autohotkey version here: ahkscript.org


Alibaba
  • Members
  • 435 posts
  • Last active: Nov 19 2014 04:21 PM
  • Joined: 01 Nov 2012
Achso, du meinst ich soll die zahl in 32 bit HEX werte aufteilen, einzeln verrechnen und am ende wieder zusammenmultiplizieren? Also verknüpfte 32 Bit integer. Das wäre ja dann das selbe was BigInteger macht, oder? :D

Find the recent autohotkey version here: ahkscript.org


nnnik
  • Members
  • 1625 posts
  • Last active: Jan 24 2019 02:19 PM
  • Joined: 28 Jul 2012

Ich habs schon fertig gehabt aber dann hab ich versehentlich meinen Browser ausgemacht...

FAIL


Visit the new forum ahkscript.org.

http://ahkscript.org


Alibaba
  • Members
  • 435 posts
  • Last active: Nov 19 2014 04:21 PM
  • Joined: 01 Nov 2012
Kann passieren.
Aber wäre cool wenn du es postest, so wie du das gemeint hast.
Ich bin noch nicht sehr weit mit dem lernen von c++.

Find the recent autohotkey version here: ahkscript.org


SAPlayer
  • Members
  • 403 posts
  • Last active: Apr 11 2014 04:45 PM
  • Joined: 06 Nov 2012

@nnnik:


Versuch mal...

/*
int stringlen(char *str)
{
  int i=0;
  for (; str[i]!=0; i++);
  return i;
}
*/
stringlen := MCode("2,x86:i0wkBDPAOAF0B0CAPAgAdfnD,x64:M8A4AXQKSP/B/8CAOQB19vPD")
MsgBox, % DllCall(stringlen, "astr", "test")

...das funktioniert bei mir.

 

Allerdings ist ein DllCall meistens langsamer, als direkt mit AHK zu berechnen oder AHK-Funktionen zu verwenden.

In diesem Fall würde ich auf jeden Fall StrLen, und keinen MCode empfehlen.

 

Vielleicht ist es also doch keine so gute Idee ^^