Hallo,
kann Cython mit Integer umgehen die größer als 256 Bit sind? Gemeint sind damit die Datentypen die man mit "cdef" festlegt. Soweit ich weiß gehen die Originalen C Datentypen nur bis zu einer Größe von 64 Bit. Python (3.3.X) kann zwar sehr viel mehr, aber wird das auch direkt von Cython unterstützt?
Cython und große (>256 Bit) Integer
@albertus: Mit ``cdef`` kann man nur C-Datentypen definieren. Darum heisst das wohl auch ``cdef``.
Folgendes geht:Ausgabe:Keine Ahnung, wie man auf Cython-Seite damit rechnet, also ob die Operatoren in Cython angepasst sind oder man auf C-Funktionen ausweichen muss.
Code: Alles auswählen
cimport cython
cpdef klaus():
cdef cython.long num = 10L
return num
Code: Alles auswählen
>>> type(klaus())
<type 'long'>
>>>
Ups, dann hat sich da einiges getan seit ich das letzte Mal Cython benutzt habe.
Hallo Jerch,jerch hat geschrieben:Folgendes geht:Ausgabe:Code: Alles auswählen
cimport cython cpdef klaus(): cdef cython.long num = 10L return num
Keine Ahnung, wie man auf Cython-Seite damit rechnet, also ob die Operatoren in Cython angepasst sind oder man auf C-Funktionen ausweichen muss.Code: Alles auswählen
>>> type(klaus()) <type 'long'> >>>
versuche mal folgendes:
Code: Alles auswählen
cpdef klaus():
cdef cython.long num = 340282366920938463463374607431768211456L
return num
Code: Alles auswählen
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = [Extension("test_big_int", ["test_big_int.pyx",])]
)
Ein Test des Moduls in IDLE erzeugt folgende Ausgabe:python3 setup.py build_ext --inplace
running build_ext
cythoning test_big_int.pyx to test_big_int.c
building 'test_big_int' extension
gcc -pthread -Wno-unused-result -DNDEBUG -fmessage-length=0 -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables -fasynchronous-unwind-tables -g -fPIC -I/usr/include/python3.3m -c test_big_int.c -o build/temp.linux-x86_64-3.3/test_big_int.o
test_big_int.c: In function ‘__pyx_f_12test_big_int_klaus’:
test_big_int.c:595:17: warning: integer constant is too large for its type [enabled by default]
gcc -pthread -shared build/temp.linux-x86_64-3.3/test_big_int.o -L/usr/lib64 -lpython3.3m -o .../test_big_int.cpython-33m.so
Getestet habe ich das jetzt unter Python 3.3.0 ich vermute es wird unter Python 2.7.2 ähnlich aussehen. Das Problem ist also c dazu zu bewegen, mit solchen und größeren Zahlen zu hantieren. Wie bekommt man das hin?>>> test_big_int.klaus()
0
>>>
Mit freundlichen Grüßen
Albertus
Albertus
@albertus: Im Grunde gar nicht. In C-Programmen würde man auf eine Bibliothek wie zum Beispiel die `libgmp` zurückgreifen. Dem C-Compiler kann man keine literalen ganzen Zahlen beibringen die grösser sind als man mit normalen ganzzahligen C-Datentypen darstellen kann. An der Stelle wird man einfach Python `int`\s verwenden müssen.
Edit: Was möchtest Du denn *eigentlich* machen?
Edit: Was möchtest Du denn *eigentlich* machen?
Tja so was habe ich mir auch schon gedacht, ich hatte allerdings die Hoffnung das Cython die Python `int\s als C `int\s verwenden würde, dem ist wohl nicht so, Schade.BlackJack hat geschrieben:@albertus: Im Grunde gar nicht. In C-Programmen würde man auf eine Bibliothek wie zum Beispiel die `libgmp` zurückgreifen. Dem C-Compiler kann man keine literalen ganzen Zahlen beibringen die grösser sind als man mit normalen ganzzahligen C-Datentypen darstellen kann. An der Stelle wird man einfach Python `int`\s verwenden müssen.
Eigentlich nichts Weltbewegendes. Aus Interesse beschäftige ich mich gerade mit Kryptographie und da ging es unter anderem auch, um das Thema Primitivwurzeln und aus einer Laune heraus kam ich auf den Gedanken, solche aus etwas größeren Zahlen zu berechnen. Mit Python war das schnell umgesetzt und ist auch schnell. Da ich aber sowieso Cython mal ausprobieren wollte, dachte ich mir, warum nicht das Skript so abändern, dass es mit Hilfe von Cython in ein C-Programm compiliert werden kann. Nun ja, dann halt nicht.BlackJack hat geschrieben: Edit: Was möchtest Du denn *eigentlich* machen?
Mit freundlichen Grüßen
Albertus
Albertus
@albertus: Cython kann die Python `int`\s nur solange in C `int`\s wandeln, solange die nicht grösser werden als der grösste Ganzzahltyp den der C-Compiler halt so kann. Und C-Compiler versuchen in der Regel bei dem zu bleiben was die CPU in einem oder maximal zwei Registern unterbringen kann. Denn nur was der Prozessor direkt kann ist schnell und in wenigen Maschinenspracheanweisungen ausgedrückt. Wenn man mehr will, braucht man dafür Subroutinen und wenn man die eh schon braucht, kann man eine Bibliothek wie `libgmp` einbinden die mit beliebig grossen Zahlen rechnen kann. Beschränkung ist natürlich der Speicher.
@albertus:
Habe das Beispiel mal mit Deiner großen Zahl probiert - nun, es funktioniert bei mir (Python 2.7, Cython 0.15.1). Daraufhin hab ich mir mal den Cython-C-code angeschaut:Damit wird klar, warum das geht - Cython transferiert die Literale zur Laufzeit mittels der PyLong_FromString-Funktion. Das macht es übringens immer so, also auch für kurze eigentlich C-gängige Längen. Interessant, dass es unter Python 3 nicht funktioniert, hier wäre der Cythoncode aufschlussreich (hab kein Python 3 hier). Die Namensgebung des Pointers finde ich kritisch, da werden diverse Compiler für sehr große Zahlen streiken (Microsoft und ICC erlauben nur 2048 Zeichen).
Man man, der Cythoncode böse mit GOTOs gespickt
@zum eigentlichen Problem:
Sowas würde ich eher in C z.B. mit GMP machen, da jedes bisschen Boilerplate bei sowas nervt und Cython die ganze Pythonschicht mitschleppen muss, was aus Problemsicht Boilerplate ist.
Habe das Beispiel mal mit Deiner großen Zahl probiert - nun, es funktioniert bei mir (Python 2.7, Cython 0.15.1). Daraufhin hab ich mir mal den Cython-C-code angeschaut:
Code: Alles auswählen
static PyObject *__pyx_int_340282366920938463463374607431768211456L;
...
__pyx_int_340282366920938463463374607431768211456L = PyLong_FromString((char *)"340282366920938463463374607431768211456", 0, 0);
Man man, der Cythoncode böse mit GOTOs gespickt
@zum eigentlichen Problem:
Sowas würde ich eher in C z.B. mit GMP machen, da jedes bisschen Boilerplate bei sowas nervt und Cython die ganze Pythonschicht mitschleppen muss, was aus Problemsicht Boilerplate ist.
@jerch: Cython benutzt GOTO in C wofür in Python ``except`` und ``finally`` benutzt werden. Das sind ja im Grunde auch eine Art Sprungmarken zu denen ”bedingungslos” gesprungen wird, wenn ein Fehler auftritt. Seit dem ich so eine Verwendung früher auch schon in anderen Programmen gesehen habe, sind meine C-Programme auch ”voll” von GOTOs, wenn es den Code an der Stelle vereinfacht, statt für jeden Fehlerrückgabecode von aufgerufenen Funktionen eine weitere Verschachtelungsebene aufzumachen.
Basierend auf BlackJack: Für Fehlerbehandlungen am Ende von Funktionen ist es ja durchaus üblich, dass man sozusagen aus einer Stelle mitten im Code mit nem GOTO im Bedarfsfall zur passenden Fehlerbehandlung - oder in C wohl meistens eher: "Abräumaktion" (`free()` bzw `DECREF()` für CPython, `fclose()` usw.) - springt. Ein solches Vorgehen kann sehr schön Code-Duplizierungen vermeiden. Verpönt ist es eigentlich nur, wenn mehrfach gesprungen wird oder wenn von unten nach oben gesprungen wird, oder ähnliche Späße.
Gut, man kann sagen, dass man sowas grundsätzlich nicht verwenden möchte, weil einem das schon zu undurchsichtig ist. Dann müsste man aber konsequenterweise auch auf `break`- und `continue`-Statements, sowie ggf noch auf `return`s innerhalb von Schleifen, verzichten. Ob das Programmieren dadurch wirklich einfacher und lesbarer wird, liegt wohl im Auge des Betrachters (um es mal halbwegs wertfrei auszudrücken).
Gut, man kann sagen, dass man sowas grundsätzlich nicht verwenden möchte, weil einem das schon zu undurchsichtig ist. Dann müsste man aber konsequenterweise auch auf `break`- und `continue`-Statements, sowie ggf noch auf `return`s innerhalb von Schleifen, verzichten. Ob das Programmieren dadurch wirklich einfacher und lesbarer wird, liegt wohl im Auge des Betrachters (um es mal halbwegs wertfrei auszudrücken).
Für solche Aufräumaktionen nutze ich frühe Returns mit entsprechenden Aufräumfunktionen (evtl. plus Errorstruct). Ein generelles Springen beim Ressourcenaufbau geht eh oft nicht, da das nötige Aufräumen von den Ressourcen, die man bereits alloziert hat, abhängt.snafu hat geschrieben:Basierend auf BlackJack: Für Fehlerbehandlungen am Ende von Funktionen ist es ja durchaus üblich, dass man sozusagen aus einer Stelle mitten im Code mit nem GOTO im Bedarfsfall zur passenden Fehlerbehandlung - oder in C wohl meistens eher: "Abräumaktion" (`free()` bzw `DECREF()` für CPython, `fclose()` usw.) - springt. Ein solches Vorgehen kann sehr schön Code-Duplizierungen vermeiden. Verpönt ist es eigentlich nur, wenn mehrfach gesprungen wird oder wenn von unten nach oben gesprungen wird, oder ähnliche Späße.
Gut, man kann sagen, dass man sowas grundsätzlich nicht verwenden möchte, weil einem das schon zu undurchsichtig ist. Dann müsste man aber konsequenterweise auch auf `break`- und `continue`-Statements, sowie ggf noch auf `return`s innerhalb von Schleifen, verzichten. Ob das Programmieren dadurch wirklich einfacher und lesbarer wird, liegt wohl im Auge des Betrachters (um es mal halbwegs wertfrei auszudrücken).
Ich hatte mal für ein Projekt mit longjmp rumhantiert, aber das ist eigentlich "GOTO gone wild", da hiermit Sprünge über Funktionen hinweg möglich werden. Hab ich ganz schnell wieder fallen gelassen, da ich meiner eigenen Codedisziplin nicht traute.
GOTOs habe ich selbst bisher nur in 2 oder 3 Fällen überhaupt eingesetzt, wobei ich damit Srünge bei komplizierten Bedingungen vereinfachen konnte (der Kommentar war dafür um so länger).
Ist wohl eine Stil-Frage. Es gibt Code, bei dem Zeiger zunächst mit NULL initalisiert werden und unter dem Label am Ende der Funktion steht dann sowas wie:
Denkbar ist hier natürlich auch ein kleines Makro a la `FREE`, das den vorherigen Test auf NULL übernimmt. Der Vorteil ist einfach, dass man für 3-4 Speicheranforderungen nicht in jedem Fehlerzweig explizit die bis dahin gemachten Alloziierungen mitbehandeln muss. Wenn etwas schiefgeht, dann macht man ein simples `goto out`. Und falls nichts schiefgeht, wird `out:` ja trotzdem abgearbeitet - also quasi Aufräumen nach Erfolg.
Aber wie gesagt: Ich will hier keinem was aufzwingen und bin auch kein regelmäßiger C-Programmierer. Neben dem persönlichen Geschmack können unter Umständen auch Performance-Frage eine Rolle spielen. Da ist natürlich jeder nicht zwingende Test einer zuviel.
Code: Alles auswählen
out:
if (foo != NULL)
free(foo);
if (bar != NULL)
free(bar);
if (baz != NULL)
free(baz);
return result;
Aber wie gesagt: Ich will hier keinem was aufzwingen und bin auch kein regelmäßiger C-Programmierer. Neben dem persönlichen Geschmack können unter Umständen auch Performance-Frage eine Rolle spielen. Da ist natürlich jeder nicht zwingende Test einer zuviel.
@snafu:
In C sollte man alle Heap-Pointer, die nicht Rückgabe einer Funktion (z.B. "Konstruktor") sind, mit NULL initialisieren (good practise). Nicht zu vergessen der nachfolgende Check, bevor man dereferenziert. Für Stackpointer ist das Ganze irrelevant.
Dein gezeigtes Szenario ist eher selten - es geht davon aus, dass man innerhalb einer Funktion (nur dort funktioniert GOTO) mehrere Heap-Pointer alloziert und am Ende wieder aufräumt. Das riecht nach "monolithischen" Funktionen mit wenig Kapselung. Ich nutze lieber "objektorientiertes" C, schreibe früh Structs mit "Konstruktoren" und "Destruktoren", wobei die Destruktoren tatsächlich eine ähnliche Struktur zu Deinem Gezeigten haben (wobei man auf Nullpointer nicht testen würde).
In C sollte man alle Heap-Pointer, die nicht Rückgabe einer Funktion (z.B. "Konstruktor") sind, mit NULL initialisieren (good practise). Nicht zu vergessen der nachfolgende Check, bevor man dereferenziert. Für Stackpointer ist das Ganze irrelevant.
Dein gezeigtes Szenario ist eher selten - es geht davon aus, dass man innerhalb einer Funktion (nur dort funktioniert GOTO) mehrere Heap-Pointer alloziert und am Ende wieder aufräumt. Das riecht nach "monolithischen" Funktionen mit wenig Kapselung. Ich nutze lieber "objektorientiertes" C, schreibe früh Structs mit "Konstruktoren" und "Destruktoren", wobei die Destruktoren tatsächlich eine ähnliche Struktur zu Deinem Gezeigten haben (wobei man auf Nullpointer nicht testen würde).
@jerch: Ich schreibe C auch eher „objektorientiert” mit Strukturen und `create_*()`- und `destroy_*()`-Funktionen und finde das Szenario gar nicht so selten. Man erstellt halt in Funktionen ab und zu mal verschiedene Objekte, zum Beispiel ein oder zwei Datenstrukturen, einen Iterator über den Daten in die Struktur(en) eingelesen werden, und dann einen weiteren über den die verarbeiteten Daten in eine Ergebnisstruktur übertragen werden, die dann zurück gegeben wird. Und alles ausser der Ergebnisstruktur muss halt am Ende der Funktion — oder im Fehlerfall — wieder aufgeräumt werden.