2013-08-17 12 views
10

Mam rodzimą bibliotekę, dla której naturalny interfejs wymagałby przekazywania potencjalnie dużych liczb. Przewiduję, że około połowa to < 32 bity; kolejny kwartał < 64 bity; następna ósma < 128 bitów - i tak dalej, bez ustalonego limitu długości.Rozszerzenie języka Python - konstruuj i sprawdzaj efektywnie duże liczby całkowite

PyLong_FromUnsignedLongLong() i PyLong_AsUnsignedLongLong() byłyby odpowiednie, gdybym mógł ograniczyć wartości do jednego rejestru.

PyLong_FromString() to pokonuje - ale przy niepożądanym wydatku wymagającym reprezentacji pośredniej. _PyLong_FromByteArray() i _PyLong_AsByteArray() zmniejszają ten koszt (czyniąc tę ​​pośrednią reprezentację prostą), ale wiodący podkreślnik sprawia, że ​​zastanawiam się, czy może to prowadzić do problemów z przenośnością.

W longintrepr.h znalazłem struct _longobject ... który sugeruje, że może to być sposób na bezpośrednią interakcję z reprezentacją wewnętrzną ... chociaż brak szczegółowej dokumentacji na temat tej struktury pozostaje przeszkodą.

Jakie podejście spowoduje optymalną przepustowość między Pythonem a biblioteką? Czy istnieje dokumentacja, którą przeoczyłem?

+2

Następnie zastosować szybki interfejs API do tych liczb, które są wystarczająco małe, a "PyLong_FromString" tylko do dużych, lub czy nie jest wystarczająco szybki ?. (Przy okazji, prawdopodobnie powinieneś oznaczyć twoje pytanie python-c-api') – dastrobu

+3

Czy profilowałeś * i * uznałeś konwersję za wąskie gardło, czy po prostu spekulujesz? Zanim znajdziesz kompleksowe rozwiązanie prostego problemu, upewnij się, że * występuje * problem. – Bakuriu

+0

Moje obawy są na etapie projektowania interfejsu API, a nie wynikiem profilowania implementacji. Szukam najmodniejszej metody (A) konstruowania obiektów PyLong w C - gdzie znam ich długość i które bity są ustawione; i (B) porównywania i testowania bitów w obiektach PyLong od C. Wciąganie ciągów w ogóle wydaje się bardzo nieporęczne, mam nadzieję znaleźć lepsze rozwiązanie. – aSteve

Odpowiedz

7

Przedrostek podkreślenia w dużej mierze oznacza to samo w C API, co w normalnym Pythonie: "ta funkcja jest przedmiotem implementacji podlegającym zmianie, więc uważaj, jeśli jej używasz". Nie ma zakazu korzystania z takich funkcji i jeśli jest to jedyny sposób na osiągnięcie określonego celu (np. Znaczący przyrost wydajności w twoim przypadku), możesz używać interfejsu API, dopóki jesteś świadomy zagrożenia.

Jeśli interfejs API _PyLong_FromByteArray był rzeczywiście prywatny, byłaby to funkcja static i nie zostałaby w pełni udokumentowana i wyeksportowana w postaci longobject.h. W rzeczywistości, Tim Peters (znany Python rdzeń deweloper) wyraźnie blesses its use:

[Dan Christensen]

Mój uczeń i ja pisząc rozszerzenie C, który produkuje dużą całkowitą w formacie binarnym które chcemy przekonwertować na długi python. Liczba bitów może być większa niż 32 lub nawet 64. Mój uczeń znalazł funkcję _PyLong_FromByteArray w longobject.h, która jest dokładnie , czego potrzebujemy, ale wiodący podkreślenie sprawia, że ​​jestem ostrożny. Czy korzystanie z tej funkcji jest bezpieczne dla ?

Python używa go wewnętrznie, więc lepiej być ;-)

będzie nadal istnieć w przyszłych wersjach Pythona?

Brak gwarancji, a to dlatego, że ma wiodącą podkreślenia: to nie oficjalnie obsługiwane, zewnętrznie udokumentowane, część reklamowanych Python/C API. Tak się składa, że ​​dodałem tę funkcję, ponieważ Python potrzebował jakiejś formy wewnętrznej funkcji w różnych modułach C w postaci .Uczynienie go oficjalną częścią Python/C API byłoby znacznie więcej pracy (na którą nie miałem czasu), a stworzył wieczne nowe obciążenie konserwacyjne (które nie jestem zainteresowany niezależnie;)).

W praktyce niewielu ludzi dotknie tej części implementacji Pythona, więc Nie oczekuję, że zniknie, a nawet zmieni się, na lata. Największą niepewnością, jaką mogę sobie wyobrazić, jest to, że ktoś może rozpocząć krucjatę, aby utworzyć inny bajtowy szereg < -> długi interfejs "oficjalny" oparty na innym sposobie reprezentowania ujemnych liczb całkowitych. Ale nawet wtedy spodziewam obecne funkcje nieoficjalne pozostać, ponieważ reprezentacja 256's-dopełnienie pozostaje niezbędna dla formatu „Q” w struct modułu, a dla protokołu modułu pickle = 2 długo formatu serializacji.

Czy jest jeszcze inna metoda, z której powinniśmy skorzystać?

Nr Dlatego funkcje te zostały wymyślone na początku ;-)

Oto dokumentacja (z Pythona 3.2.1):

/* _PyLong_FromByteArray: View the n unsigned bytes as a binary integer in 
    base 256, and return a Python long with the same numeric value. 
    If n is 0, the integer is 0. Else: 
    If little_endian is 1/true, bytes[n-1] is the MSB and bytes[0] the LSB; 
    else (little_endian is 0/false) bytes[0] is the MSB and bytes[n-1] the 
    LSB. 
    If is_signed is 0/false, view the bytes as a non-negative integer. 
    If is_signed is 1/true, view the bytes as a 2's-complement integer, 
    non-negative if bit 0x80 of the MSB is clear, negative if set. 
    Error returns: 
    + Return NULL with the appropriate exception set if there's not 
    enough memory to create the Python long. 
*/ 
PyAPI_FUNC(PyObject *) _PyLong_FromByteArray(
    const unsigned char* bytes, size_t n, 
    int little_endian, int is_signed); 

Głównym powodem jest to " podkreślenie-prefiks "API polega na tym, że zależy to od implementacji Pythona long jako tablicy słów w potędze dwubajtowej. Prawdopodobnie to się nie zmieni, ale od kiedy implementujesz API, możesz zaizolować dzwoniących przed zmianami w API Pythona.

+0

Bardzo pomocne informacje na temat metody _PyLong_FromByteArray() .Dzięki. Chciałbym jeszcze ustalić, czy istnieje równie realistyczne podejście, które jest jeszcze bardziej bezpośrednie.Mogę przejść przez tablicę bajtów (w obu kierunkach), ale wolałbym interakcję bezpośrednio z tablicą "kończyn" - w sposób analogiczny do użycia GMP/MPIR - szczególnie podczas czytania dużych liczb całkowitych w C. – aSteve

+0

@ aSteve: Nie bez użycia jeszcze bardziej prywatnego API, obawiam się. 'longintrepr.h' definiuje' struct _longobject', a nad nim jest ładny, duży blok dokumentacji. Jedyną częścią, która może wyglądać dziwnie, jest 'PyObject_VAR_HEAD', która jest [dobrze udokumentowana] (http://docs.python.org/release/3.0/c-api/structures.html#PyObject_VAR_HEAD). Oczywiście, jeśli faktycznie używasz 'longintrepr.h', jesteś odpowiedzialny za śledzenie wszelkich możliwych złamań API. – nneonneo

0

Wygląda na to, że potrzebujesz PyNumber_Long. Niektóre trafienia do dokumentów to here.

+0

Wierzę, że OP chce dokonać konwersji między Typy C i obiekty Pythona, dlatego nie może używać 'PyNumber_Long'. – Bakuriu

+0

Znalazłem Pythona" Protokół Numerowy "- udostępniający procedury numeryczne obejmujące długie numery Pythona ... ale nie widzę żadnych funkcji, które pomogłyby mi wydajnie/sprawdź te obiekty od C. – aSteve