Generování číslice odmocnině 2

hlasů
16

Chci vytvořit číslice druhé odmocniny dva až tři miliony znaků.

Jsem si vědom Newton-Raphsonova ale nemám moc ponětí, jak to provést v C nebo C ++ vzhledem k nedostatku podpory BigInteger. Může mi někdo ukázat správným směrem?

Také, pokud někdo ví, jak to udělat v Pythonu (jsem začátečník), také bych si toho vážím.

Položena 03/03/2011 v 23:56
zdroj uživatelem
V jiných jazycích...                            


9 odpovědí

hlasů
3

Pokud jde o svévolné velkými čísly můžete se podívat na GNU Multiple Precision aritmetické knihovny (pro C / C ++).

Odpovězeno 03/03/2011 v 23:59
zdroj uživatelem

hlasů
3

Pro práci? Použití knihovny!

Pro zábavu? Dobré pro tebe :)

Napište program napodobit to, co by dělat s tužkou a papírem. Začínat číslicí 1, pak 2 míst, pak 3, ..., ...

Nebojte se o Newton nebo kdokoli jiný. Prostě to udělej svou cestu.

Odpovězeno 04/03/2011 v 00:04
zdroj uživatelem

hlasů
0

Python již podporuje velké celá čísla ven z krabice, a pokud je to jediné, co drží zpátky v C / C ++ vždy můžete rychle napsat kontejner třídy sami.

Jediný problém, že jste zmínil, je nedostatek velkých čísel. Pokud si nechcete použít knihovnu pro to, pak hledáte pomoc psaní takovou třídu?

Odpovězeno 04/03/2011 v 00:16
zdroj uživatelem

hlasů
7

EDIT : Mám rád tuto verzi lepší než ta předchozí. To je obecně řešení, které přijímá jak celá čísla a desetinné zlomky; s n = 2 a přesnost = 100000, trvá přibližně dvě minuty. Díky Paul McGuire pro jeho návrhy a dalšími návrhy vítány!

def sqrt_list(n, precision):
    ndigits = []        # break n into list of digits
    n_int = int(n)
    n_fraction = n - n_int

    while n_int:                            # generate list of digits of integral part
        ndigits.append(n_int % 10)
        n_int /= 10
    if len(ndigits) % 2: ndigits.append(0)  # ndigits will be processed in groups of 2

    decimal_point_index = len(ndigits) / 2  # remember decimal point position
    while n_fraction:                       # insert digits from fractional part
        n_fraction *= 10
        ndigits.insert(0, int(n_fraction))
        n_fraction -= int(n_fraction)
    if len(ndigits) % 2: ndigits.insert(0, 0)  # ndigits will be processed in groups of 2

    rootlist = []
    root = carry = 0                        # the algorithm
    while root == 0 or (len(rootlist) < precision and (ndigits or carry != 0)):
        carry = carry * 100
        if ndigits: carry += ndigits.pop() * 10 + ndigits.pop()
        x = 9
        while (20 * root + x) * x > carry:
                x -= 1
        carry -= (20 * root + x) * x
        root = root * 10 + x
        rootlist.append(x)
    return rootlist, decimal_point_index
Odpovězeno 04/03/2011 v 00:33
zdroj uživatelem

hlasů
2

Zde je zkrácená verze pro výpočet druhé odmocniny celočíselnou A do číslic přesnosti. Působí tak, že nalezení celočíselnou odmocninu po vynásobení 10 zvýšena na 2 x číslice .

def sqroot(a, digits):
    a = a * (10**(2*digits))
    x_prev = 0
    x_next = 1 * (10**digits)
    while x_prev != x_next:
        x_prev = x_next
        x_next = (x_prev + (a // x_prev)) >> 1
    return x_next

Jen několik námitek.

Budete muset převést výsledek na řetězec a přidat desetinnou čárku na správném místě (chcete-li desetinnou čárku tisku).

Převod velké číslo na řetězec není příliš rychlý.

Dělení velmi velká celá čísla není příliš rychle (v Pythonu) buď.

V závislosti na výkonu vašeho systému, může to trvat hodinu nebo déle pro výpočet druhé odmocniny 2 až 3 miliony desetinná místa.

I neprokázaly smyčka bude vždy ukončit. To může oscilovat mezi dvěma hodnotami, které se liší poslední číslici. Nebo to nemusí.

Odpovězeno 04/03/2011 v 06:00
zdroj uživatelem

hlasů
3

Nejhezčí cesta je pravděpodobně pomocí řetězovým zlomkem expanze [1; 2, 2, ...]druhá odmocnina ze dvou.

def root_two_cf_expansion():
    yield 1
    while True:
        yield 2

def z(a,b,c,d, contfrac):
    for x in contfrac:
        while a > 0 and b > 0 and c > 0 and d > 0:
            t = a // c
            t2 = b // d
            if not t == t2:
                break
            yield t
            a = (10 * (a - c*t))
            b = (10 * (b - d*t))
            # continue with same fraction, don't pull new x
        a, b = x*a+b, a
        c, d = x*c+d, c
    for digit in rdigits(a, c):
        yield digit

def rdigits(p, q):
    while p > 0:
        if p > q:
           d = p // q
           p = p - q * d
        else:
           d = (10 * p) // q
           p = 10 * p - q * d
        yield d

def decimal(contfrac):
    return z(1,0,0,1,contfrac)

decimal((root_two_cf_expansion())vrací iterátor všech desetinných míst. t1a t2v algoritmu jsou minimální a maximální hodnoty na další číslici. Když jsou si rovny, můžeme výstup, který číslice.

Všimněte si, že tento nezpracovává některých výjimečných případech, jako je záporná čísla v pokračující frakce.

(Tento kód je adaptace Haskell kódu pro manipulaci s pokračující frakce, která byla plovoucí kolem.)

Odpovězeno 04/03/2011 v 07:05
zdroj uživatelem

hlasů
0

Zde je účinnější číslo odmocnina (v Pythonu 3.x), který by měl ukončit ve všech případech. Začíná s řadou mnohem blíže k druhé odmocnině, takže to trvá méně kroků. Všimněte si, že int.bit_length vyžaduje Python 3.1 nebo novější. Kontrola chyb vynechal pro stručnost.

def isqrt(n):
    x = (n >> n.bit_length() // 2) + 1
    result = (x + n // x) // 2
    while abs(result - x) > 1:
        x = result
        result = (x + n // x) // 2
    while result * result > n:
        result -= 1
    return result
Odpovězeno 04/03/2011 v 12:40
zdroj uživatelem

hlasů
8

Mohli byste zkusit pomocí mapování:

a/b -> (a+2b)/(a+b)počínaje a= 1, b= 1. Tento konverguje k sqrt (2) (ve skutečnosti poskytuje řetězový zlomek reprezentace ní).

Nyní je klíčovým bodem: Toto může být reprezentován jako maticové násobení (podobné Fibonacci)

Pokud a_n a b_n jsou nth čísla v krocích poté

[1 2] [a_n b_n] T = [a_ (n + 1) b_ (n + 1)] T
[1 1]

která nyní nám dává

[1 2] n [a_1 b_1] T = [a_ (n + 1) b_ (n + 1)] T
[1 1]

Tedy pokud je 2x2 matice je A, musíme počítat A n , které lze provést opakovaným kvadratura a používá pouze celočíselné aritmetiky (takže nemusíte mít strach o přesných otázek).

Všimněte si také, že A / B, které se zobrazí bude vždy v redukované formě (jako gcd (a, b) = gcd (a + 2b, a + b)), takže v případě, že na mysli použití třídu frakce reprezentovat meziproduktu výsledky, ne!

Vzhledem k tomu, že nth jmenovatelem je jako (1 + sqrt (2)) ^ n, aby se 3 miliony číslice byste pravděpodobně potřebovat počítat až do 3.671.656 tého období.

Všimněte si, že i když jste hledali na ~ 3,6 miliontý horizontu bude opakován kvadratura umožní vypočítat n-tý výraz v O (log n), násobení a sčítání.

Také to může být snadno provedena paralelně, na rozdíl od těch, iterační jako Newton-Raphsonovy atd

Odpovězeno 04/03/2011 v 17:08
zdroj uživatelem

hlasů
2

No, následující je kód, který jsem napsal. Je generována milionu číslic za desetinnou čárkou za druhé odmocniny 2 v asi 60800 vteřin na mě, ale můj notebook spal, když byl spuštěn program, mělo by být rychlejší, že. Můžete se pokusit generovat 3 miliony míst, ale může to trvat několik dní, aby si to.

def sqrt(number,digits_after_decimal=20):
import time
start=time.time()
original_number=number
number=str(number)
list=[]
for a in range(len(number)):
    if number[a]=='.':
        decimal_point_locaiton=a
        break
    if a==len(number)-1:
        number+='.'
        decimal_point_locaiton=a+1
if decimal_point_locaiton/2!=round(decimal_point_locaiton/2):
    number='0'+number
    decimal_point_locaiton+=1
if len(number)/2!=round(len(number)/2):
    number+='0'
number=number[:decimal_point_locaiton]+number[decimal_point_locaiton+1:]
decimal_point_ans=int((decimal_point_locaiton-2)/2)+1
for a in range(0,len(number),2):
    if number[a]!='0':
        list.append(eval(number[a:a+2]))
    else:
        try:
            list.append(eval(number[a+1]))
        except IndexError:
            pass
p=0
c=list[0]
x=0
ans=''
for a in range(len(list)):
    while c>=(20*p+x)*(x):
        x+=1
    y=(20*p+x-1)*(x-1)
    p=p*10+x-1
    ans+=str(x-1)
    c-=y
    try:
        c=c*100+list[a+1]
    except IndexError:
        c=c*100
while c!=0:
    x=0
    while c>=(20*p+x)*(x):
        x+=1
    y=(20*p+x-1)*(x-1)
    p=p*10+x-1
    ans+=str(x-1)
    c-=y
    c=c*100
    if len(ans)-decimal_point_ans>=digits_after_decimal:
            break
ans=ans[:decimal_point_ans]+'.'+ans[decimal_point_ans:]
total=time.time()-start
return ans,total
Odpovězeno 09/08/2011 v 23:24
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more