Wątek przeniesiony 2020-06-22 10:23 z C/C++ przez Shalom.

liczby złożone

0

Cześć!
Udało mi się wymyślić i napisać algorytm który rozbiera liczbę na dwa czynniki
nawet jeśli są pierwsze. Tylko jeśli liczby składowe nie sią od siebie dalej niż
w przybliżeniu pierwiastek z a. a*b, a<b, b w przybliżeniu mniejsze od
a+1000*sqrt(a) .Ale za to algoryt jeśli mówimy o małych liczbach złożonych
np.100cyfrowych 500cyfrowych 5000cyfrowych działa błyskawicznie. Natomiast jeśli
chodzi o liczby złożone 100tysięczno cyfrowe 200tysięcznocyfrowe zaczynają się
małe schody i przy tych liczbach najlepiej aby składowe były bliżej siebie czyli
b wprzybliżeniu mniejsze od a+10*sqrt(a) albo najlepiej od a+sqrt(a).
Oczywiście zależy to od procesora cześć kodu można podzielić na wątki właśnie
dziele ten program bo mam 4 rdzenie 8 wątków i sprawdzę wydajność.A zupełnie
lepiej by to chodziło np. jak znałbym programowanie na kartach graficznych.
To tak w skrócie. Czyli jeśli dacie mi liczbę np.która będzie złożona na
przykład.

1234567890123456789012345678900987654321098765432187897213984701293487102398471092384710293487109233 *
1234567890123456789012345678900987654321098765432170129348710239847109238471029348710923389787398321
=c.

(zwróćcie uwagę do połowy się te liczby zgadzają)
to mój algorytm z tego c rozłoży na te liczby składowe w ułamek sekundy.
Pytanie do was do czego to może się przydać do czego byście to użyli w
programowaniu może do jakiegoś szyfrowania czy kompresowania albo innych spraw.
Nie ukrywam że chciałbym na tym jakoś zarobić bo rozwiązanie nie wydaje się
tuzinkowe :D

9

Na oko "odkryłeś" faktoryzacje metodą Fermata. Nie pokazłeś ani linijki kodu, ale założenia mocno to sugerują. https://pl.wikipedia.org/wiki/Algorytm_Fermata
Niestety spóźniłeś się o jakieś 400 lat :(

def fermat_factors(n):
    assert n % 2 != 0
    import gmpy2
    a = gmpy2.isqrt(n)
    b2 = gmpy2.square(a) - n
    while not gmpy2.is_square(b2):
        a += 1
        b2 = gmpy2.square(a) - n
    factor1 = a + gmpy2.isqrt(b2)
    factor2 = a - gmpy2.isqrt(b2)
    print(n, factor1, factor2)
    return int(factor1), int(factor2)

Ewentualnie dla takiego przypadku który podałeś można też faktoryzować za pomocą metody Coppersmitha/LLL na zasadzie:

hidden = N.nbits()/2
p_approx = isqrt(N)
q_approx = p_approx + 2**hidden
F.<x> = PolynomialRing(Zmod(N), implementation='NTL')
f = x - q_approx
d = f.small_roots(X=2**hidden, beta=0.5)[0]
print(q_approx - d, q_approx + d)

ale ta druga metoda jest bardziej uniwersalna, bo działa generalnie dla dowolnej aproksymacji p lub q. Tzn jeśli umiesz aproksymować któryś z czynników tak że "brakuje" ci nie więcej niż N^beta/2 bitów, to będzie działać.

0

Hmm no nie źle 400 lat się spóźniłem. Muszę to sprawdzić czy ten algorytm zadziała równie szybko co mój i czy da radę z tak dużymi liczbami

0

Działa chyba całkiem szybko :p

In [33]: p = random.randrange(2**1000000) | 1  # to żeby liczba była nieparzysta

In [34]: q = (p + random.randrange(2**500000)) | 1 # to również

In [35]: %timeit fermat_factors(p*q)
132 ms ± 2.28 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
0

Nie mój algorytm dzała inaczej liczby nie musza być blisko pierwiastka ani nie polegaja na losowości czegokilwiek. Czy ten algorytm w sekundę rozłoży np. Ten przykĺad który dałem. Musze jescz poprawić kod troche ale moim sposobem nawet pół miliono cyfrowe liczby to powinien być uĺamek sek jeśli tylko tak jak pisalem a<b i b w pryzbliżeniu nie przekracza a +10pierwiastków z a.

0

liczby nie musza być blisko pierwiastka

i

a<b i b w pryzbliżeniu nie przekracza a +10pierwiastków z a

się wyklucza :)

Jeśli masz dwie liczby które są blisko siebie (a u ciebie wymuszasz ze nie mogą się różnić o więcej niż jakieś 10+sqrt(a), czyli różnią się na nie więcej niż połowie dolnych bitów) to muszą być blisko (czyli różnić się znów w tym przypadku jedynie na dolnej połowie bitów) pierwiastka z iloczynu. To jest matematyka na poziomie szkoły podstawowej.
Weźmy twój przykład:

x = 1234567890123456789012345678900987654321098765432187897213984701293487102398471092384710293487109233 *1234567890123456789012345678900987654321098765432170129348710239847109238471029348710923389787398321
gmpy2.isqrt(x)
mpz(1234567890123456789012345678900987654321098765432179013281347470570298170434750220547816841637253776L)

Jak nie trudno zauważyć, dostaliśmy liczbę która ma wszystkie górne bity takie same jak "wspólna" część twoich wejściowych liczb. Generalnie pierwiastek będzie mniej więcej w połowie między twoimi czynnikami p i q.

Czy ten algorytm w sekundę rozłoży np. Ten przykĺad który dałem

Rozłoży rzędy wielkości szybciej i to nawet biorąc pod uwagę ze to wieśniacka implementacja w pythonie. Na moim laptopie średnia z miliona uruchomień to 5.87 mikrosekundy. W sekundę można by to uruchomić 200 tysięcy razy.

Jeszcze raz: jestem pewien ze twój algorytm polega na tej samej zasadzie, nawet jeśli liczysz to w bardziej nieudolny sposób. Jasno wskazują na to ograniczenia które nakładasz na różnicę między czynnikami.

Dobra a teraz zniszczę twoje marzenia o fortunie :D Widać dość jasno, ze twoje założenie a<b i b w pryzbliżeniu nie przekracza a +10pierwiastków z a oznacza, że pierwiastek z n pozwala nam odzyskać połowę górnych bitów p oraz q (bo są takie same). Czyli innymi słowy twoja metoda (vel metoda Fermata) pozwala na faktoryzacje jeśli znamy aż połowę bitów p oraz q. To jest dość mocne założenie. Pokaże ci teraz metodę (wspominałem o niej wyżej), która potrafi dokonać faktoryzacji znając połowę bitów (górnych lub dolnych, bez różnicy) tylko jednego z czynników i nie nakłada żadnych (!) ograniczeń na drugi czynnik, ani na różnicę między czynnikami. Siłą rzeczy jest znacznie mocniejsza niż to o czym dotąd pisaliśmy:

bits = 512
hidden = 215

# dwa losowe dowolne prime
p = random_prime(2^bits-1, false, 2^(bits-1))
q = random_prime(2^bits-1, false, 2^(bits-1))
# dla pewnosci pokazujemy ze roznia sie praktycznie na wszystkich bitach!
print((p-q).nbits())
# bierzemy sobie p>q, to bez roznicy ale trzeba by pozniej liczyc 2 razy w zaleznosci od przypadku
if q > p:
    tmp = p
    p = q
    q = tmp

# kasujemy dolne hidden bitow z liczby p
p_approx = (p >> hidden) << (hidden)

print('p', hex(p))
print('p_approx', hex(p_approx))
print('q', hex(q))

N = p*q
F.<x> = PolynomialRing(Zmod(N), implementation='NTL')
f = x + p_approx
d = f.small_roots(X=2^hidden, beta=0.5)[0]
print('recovered', hex(int(p_approx + d)))

(zeby dostać więcej hidden bitów trzeba by troche podkręcic parametry i liczyłoby sie dłużej, ale górna granica to właśnie połowa bitów, o ile znamy przynajmniej połowę, algorytm się policzy w czasie wielomianowym)

0

No to klapa trzeba dalej kombinować. Być może mój algorytm działa podobnie tego się chciałem dowiedzieć a jak to będzie w C++? :)

1

Użyta biblioteka NTL ma tutaj swoją stronę domową (i przypadkiem jest napisana w C++, więc masz szczęście)

https://www.shoup.net/ntl/

0

Dzieki! A słuchajcie jak już tak sobie gadamy nie często tu wchodzę ale podpowiedzcie mi w wolnej chwili... prawdopodobnie to też nie żadne odkrycie ale wyszukuję i nie moge jakoś wyszukać. Jest metoda jakaś na szybkie znalezienie liczbzy któara jest czynnikiem a i b. Czyli dokladnie jak byśmy skracali licznik i mianownik najwieksym wspólnym dzielnikiem. Jest jakaś metoda na duże liczby?

2

Nie rozumiem pytania. Przecież sam sobie odpowiedziałeś -> gcd da ci największy wspólny dzielnik a i b i działa bardzo dobrze nawet dla dużych liczb. Oczywiście jak zaimplementujesz to po ludzku...

0

Nie już znalazłem algorytm euklidesa. Tylko ja wymyśliłem przez modulo po co to odejmować :D modulo naprzemienne jeśli na końcu jest 0 to liczba przed jesr najwiszy wspólny dzielnik obu liczb jeśli 1 to nie ma żadnego nie ważne nie było tematu. Idę kombinować jak rozłożyć duże liczby na czynniki pierwsze od razu a nie tam na piechtę :D

2

Tylko ja wymyśliłem przez modulo po co to odejmować

I tak się to robi właśnie. Z odejmowaniem to chyba w podstawówce uczyli bo dzieci nie wiedzą co to modulo...

Idę kombinować jak rozłożyć duże liczby na czynniki pierwsze od razu a nie tam na piechtę

Ja bym zaczął może od poczytania na ten temat zanim znowu wymyślisz metodę znaną od setek lat ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1