def shanks_worst_tests(numOfTests: int, numOfBits: list, randSeed=0):
    seed(randSeed)
    total_steps_class_list, times_clasic_list, total_memory_clasic = [], [], []
    total_steps_grumpy_list, times_grumpy_list, total_memory_grumpy = [], [], []
    for bits in numOfBits:
        time_clas, time_grumpy = [], []
        steps_clas, steps_grumpy = [], []
        mem_clas, mem_grumpy = [], []
        print("Started: ", bits)
        if bits >= 50:
            numOfTests = 50
        elif bits >= 40:
            numOfTests = 100
        for iter in range(numOfTests):
            p, g, exp, h = gnp.worst_shanks_numbers(bits)
            t = timer()
            x_c, small_clas, giant_clas, mem_c = shanks_classic(g, h, p, p - 1)
            steps_clas.append(small_clas + giant_clas)
            mem_clas.append(mem_c)
            passed_time = (timer() - t) * 1000
            time_clas.append(passed_time)

            t = timer()
            x_c, oper, mem_c = shanks_two_grumpys_one_baby(g, h, p, p - 1)
            if x_c != exp:
                print("NG")
            steps_grumpy.append(oper)
            mem_grumpy.append(mem_c)
            passed_time = (timer() - t) * 1000
            time_grumpy.append(passed_time)
        print(
            f"Avg steps clasic:{avg(steps_clas) / ceil(sqrt(p)):.4f} -- Avg steps grumpy:{avg(steps_grumpy) / ceil(sqrt(p)):.4f}"
        )
        print(
            f"Avg memory clasic:{avg(mem_clas) / ceil(sqrt(p)):.4f} -- Avg memory grumpy:{avg(mem_grumpy) / ceil(sqrt(p)):.4f}"
        )
        print(
            f"Avg time clasic:{avg(time_clas):.4f} -- Avg time grumpy:{avg(time_grumpy):.4f}"
        )
        total_steps_class_list.append(avg(steps_clas) / ceil(sqrt(p)))
        total_steps_grumpy_list.append(avg(steps_grumpy) / ceil(sqrt(p)))
        times_clasic_list.append(avg(time_clas))
        times_grumpy_list.append(avg(time_grumpy))
        total_memory_clasic.append(avg(mem_clas) / ceil(sqrt(p)))
        total_memory_grumpy.append(avg(mem_grumpy) / ceil(sqrt(p)))
        print(f"Finished: {bits}\n")

    print(
        f"Avg steps clasic:{avg(total_steps_class_list):.4f} -- Avg steps grumpy:{avg(total_steps_grumpy_list):.4f}"
    )
    print(
        f"Avg memory clasic:{avg(total_memory_clasic):.4f} -- Avg memory grumpy:{avg(total_memory_grumpy):.4f}"
    )
    print(
        f"Avg time clasic:{avg(times_clasic_list):.4f} -- Avg time grumpy:{avg(times_grumpy_list):.4f}"
    )
Beispiel #2
0
def shanks_interleved(g, h, p, ordin):
  n = ceil(sqrt(ordin))
  e = 1
  u = pow(g, p - n - 1, p)
  s = h
  baby, giant = {e:0}, {s:0}
  # lista = {e:0, s:0}
  for j in range(1, n + 1):
    e = (e * g) % p
    if e == h:
      return j, 2 * j + 1, getsizeof(baby) + getsizeof(giant) #getsizeof(lista)
    else:
      i = giant.get(e, None)
      # i = lista.get(e, None)
      if i:
        return (j + i*n) % ordin, 2 * j + 1, getsizeof(baby) + getsizeof(giant) #getsizeof(lista)
      else:
        baby[e] = j
        # lista[e] = j
      s = (s * u) % p
      i = baby.get(s, None)
      # i = lista.get(s, None)
      if i:
        return (j*n + i) % ordin, 2 * (j + 1), getsizeof(baby) + getsizeof(giant)#getsizeof(lista)
      else:
        giant[s] = j
        # lista[s] = j
  return None
Beispiel #3
0
def shanks_centered(g, h, p, ordin):
  n = ceil(sqrt(ordin))
  K = ordin // 2
  small_steps = 1
  e = pow(g, K, p)
  lista = {e: 0}
  for j in range(1, n):
    e = (e * g) % p
    if e == h:
      return K + j, small_steps, 0
    else:
      lista[e] = j
      small_steps += 1
  u = pow(g, p - n - 1, p)
  s = pow(g, n, p)
  ep = em = h
  for i in range(0, n):
    try:
      j = lista[em]
      return j + K - i * n, small_steps, 2 * (i + 1)
    except KeyError:
      try:
        j = lista[ep]
        return K + j + i * n, small_steps, 2 * (i + 1)
      except KeyError:
        ep = (ep * u) % p
        em = (em * s) % p
  return None
Beispiel #4
0
def shanks_order_unkown(g, h, p):
  rad_p = ceil(sqrt(p - 1))
  n = 100
  lista_n = []
  while n < rad_p:
    lista_n.append(n)
    n *= 10
  lista_n.append(rad_p)
  last_n = 1
  e = 1
  lista = {e: 0}
  for n in lista_n:
    for j in range(last_n, n + 1):
      e = (e * g) % p
      if e == h:
        return j
      lista[e] = j

    u = pow(g, p - n - 1, p)
    l = h
    for i in range(0, n + 1):
      try:
        j = lista[l]
        return i * n + j
      except KeyError:
        l = (l * u) % p
    last_n = n + 1
  return None
def primes_up_to_B(B: int):
    a = [1] * B
    for i in range(2, ceil(sqrt(B))):
        if a[i]:
            for j in range(i * i, B, i):
                a[j] = 0
    return [i for i in range(len(a)) if a[i] == 1][2:]
Beispiel #6
0
def shanks_two_grumpys_one_baby(g, h, p, ordin):
  n = ceil(sqrt(ordin))
  m = ceil(n/2)
  u = pow(g, m, p)
  s = pow(g, p - (m + 1) - 1, p)
  b = 1
  giant1 = h
  giant2 = pow(h, 2, p)
  babys, giants1, giants2 = {b: 0}, {giant1: 0}, {giant2: 0}
  for i in range(1, n + 1):
    b = (b * g) % p
    if b == h:
      return i, 3 * (i - 1) + 1, getsizeof(babys) + getsizeof(giants1) + getsizeof(giants2)
    else:
      j = giants1.get(b, None)
      if j:
        return (i - j * m) % ordin, 3 * (i - 1) + 1, getsizeof(babys) + getsizeof(giants1) + getsizeof(giants2)
      else:
        j = giants2.get(b, None)
        if j:
          r = (i + j * (m + 1)) // 2
          l = ordin // 2
          for _ in range(3):
            if pow(g, r, p) == h:
              return r, 3 * (i - 1) + 1, getsizeof(babys) + getsizeof(giants1) + getsizeof(giants2)
            r += l
        else:
          babys[b] = i

    giant1 = (giant1 * u) % p
    j = babys.get(giant1, None)
    if j:
      return (j - i * m) % ordin, 3 * (i - 1) + 2, getsizeof(babys) + getsizeof(giants1) + getsizeof(giants2)
    else:
      j = giants2.get(giant1, None)
      if j:
        return (i * m + j * (m + 1)) % ordin, 3 * (i - 1) + 2, getsizeof(babys) + getsizeof(giants1) + getsizeof(giants2)
      else:
        giants1[giant1] = i

    giant2 = (giant2 * s) % p
    j = babys.get(giant2, None)
    if j:
      r = (j + i * (m + 1)) // 2
      l = ordin // 2
      for _ in range(3):
        if pow(g, r, p) == h:
          return r, 3 * i , getsizeof(babys) + getsizeof(giants1) + getsizeof(giants2)
        r += l
    else:
      j = giants1.get(giant2, None)
      if j:
        return (j * m + i * (m + 1)) % ordin, 3 * i, getsizeof(babys) + getsizeof(giants1) + getsizeof(giants2)
      else:
        giants2[giant2] = i
  return None
def worst_shanks_numbers(numOfBits: int):
    prime = get_primes(numOfBits, 1)[0]
    while prime < 10:
        prime = get_primes(numOfBits, 1)[0]
    generator = artmod.generator_Zp(prime)
    n = math.ceil(artmod.sqrt(prime - 1))
    exp = n * (n - 1)
    if exp >= prime - 1:
        exp = n * (n - 2)
    h = pow(generator, exp, prime)
    return prime, generator, exp, h
Beispiel #8
0
def shanks_classic_better_avg(g, h, p, ordin):
  n = ceil(sqrt(ordin/2))
  e = 1
  lista = {e: 0}
  for j in range(1, n):
    e = (e * g) % p
    if e == h:
      return j, j, 0, getsizeof(lista)
    else:
      lista[e] = j
  u = pow(g, p - n - 1, p)
  e = h
  for i in range(0, 2 * n):
    try:
      j = lista[e]
      return i * n  + j, n, i + 1, getsizeof(lista)
    except KeyError:
      e = (e * u) % p
  return None
Beispiel #9
0
def shanks_classic_binary_search(g, h, p, ordin):
  n = ceil(sqrt(ordin))
  small_steps = 1
  e = 1
  lista = [(e,0)]
  for j in range(1, n):
    e = (e * g) % p
    if e == h:
      return j, small_steps, 0, getsizeof(lista)
    else:
      lista.append((e,j))
      small_steps += 1
  lista.sort(key=lambda x: x[0])
  u = pow(g, p - n - 1, p)
  e = h
  for i in range(0, n):
    j = find_index(lista, e)
    if j != None:
      return i * n  + j, small_steps, i + 1, getsizeof(lista)
    else:
      e = (e * u) % p
  return None
Beispiel #10
0
def shanks_classic(g, h, p, ordin):
  n = ceil(sqrt(ordin))
  e = 1
  lista = {e: 0}
  dict_limit = 1.15 * (10 ** 10)
  for j in range(1, n):
    if getsizeof(lista) > dict_limit:
      return None, None, None, None
    e = (e * g) % p
    if e == h:
      return j, j, 0, getsizeof(lista)
    else:
      lista[e] = j
  u = pow(g, p - n - 1, p)
  e = h
  for i in range(0, n):
    try:
      j = lista[e]
      return i * n  + j, n, i + 1, getsizeof(lista)
    except KeyError:
      e = (e * u) % p
  return None
Beispiel #11
0
def optim_factors(ordin):
  factori = [pow(x, e) for x, e in factorint(ordin).items()]
  factori.sort()
  if len(factori) == 1:
    return Shanks_ordin_cunoscut(g, h, p, ordin)
  if len(factori) == 2:
    l = ceil(sqrt(factori[1]))
    m = ceil(sqrt(factori[0]))
  else:
    fact_1 = reduce(mul, factori[:-1])
    if fact_1 > factori[-1]:
      l = ceil(sqrt(fact_1))
      m = ceil(sqrt(factori[-1]))
    else:
      l = ceil(sqrt(factori[-1]))
      m = ceil(sqrt(fact_1))
  return l, m
Beispiel #12
0
def shanks_classic_with_memory(g, h_values, p, ordin):
  n = ceil(sqrt(ordin))
  small_steps = 1
  e = 1
  lista = {e: 0}
  for j in range(1, n):
    e = (e * g) % p
    lista[e] = j
    small_steps += 1

  u = pow(g, p - n - 1, p)
  exponents, giant_steps_list = [], []
  for h in h_values:
    e = h
    for i in range(0, n):
      try:
        j = lista[e]
        exponents.append(i * n + j)
        giant_steps_list.append(i + 1)
        break
      except KeyError:
        e = (e * u) % p
  return exponents, small_steps, giant_steps_list, getsizeof(lista)
    return exponents[-1] % (p - 1), t_cong, it


if __name__ == '__main__':
    i = 0
    ts, tts = [], []
    its = []
    seed(42)
    for q in range(5):
        for _ in range(500):
            ok = 1
            while ok:
                ok = 0
                p, g, exponent, h = logarithm_test_numbers(15, safe=False)
            x = 2**ceil(log2(p - 1))
            B = ceil(exp(1 / sqrt(2) * sqrt(log(x) * log(log(x)))) / 2)
            # print(L(p), shanks_complex(p))
            primesB = primes_up_to_B(B)
            max_equations = primes_upto(B) + 5
            # print(B, max_equations, p)
            t = timer()
            x, ta, it = SELD_lect11(g, h, p, B, max_equations, primesB, 42)
            ts.append((timer() - t) * 1000)
            its.append(it)
            if x == exponent:
                # print("DA")
                i += 1
            else:
                if pow(g, x, p) != h:
                    print("Nu")
        avg_ts = avg(ts)
from aritmetica_modulara import sqrt, extended_euclid, avg
from math import gcd, ceil, floor
import random as rand
from functools import partial
from sys import getsizeof

A = (sqrt(5) - 1) / 2


def found_match(g, h, p, a_x, a_y, b_x, b_y):
    u = (a_x - a_y) % (p - 1)
    v = (b_y - b_x) % (p - 1)
    if v == 0:
        return None
    d, s, t = extended_euclid(v, p - 1)
    if d == 1:
        return (u * s) % (p - 1)
    else:
        # print("D: ",d)
        w = ((u * s) % (p - 1)) // d
        sol_pos = [w] + [(w + k * ((p - 1) // d)) % (p - 1)
                         for k in range(1, d)]
        for sol in sol_pos:
            if pow(g, sol, p) == h:
                return sol
    return None


def hash_function(num, r):
    return floor(((A * num) % 1) * r) + 1
def test_pollard(numOfTests: int,
                 listOfBits: list,
                 contests: dict,
                 img_path: str,
                 rand_seeds=[0]):
    import matplotlib.pyplot as plt
    from matplotlib.lines import Line2D
    from itertools import cycle
    marker = cycle(rand.sample(Line2D.markers.keys(), len(contests)))
    plt.tight_layout(pad=0.05)

    times = [[[0 for _ in rand_seeds] for _ in contests] for _ in listOfBits]
    times_avg = [[0 for _ in contests] for _ in listOfBits]
    iterations = [[[0 for _ in rand_seeds] for _ in contests]
                  for _ in listOfBits]
    iterations_avg = [[0 for _ in contests] for _ in listOfBits]

    for ind_b, bits in enumerate(listOfBits):
        print("Bits: ", bits)
        tests = num_of_tests(bits, numOfTests)
        print("Nr of tests: ", tests)
        p_set = set()
        print("Seed: ", end='')
        for ind_s, seed in enumerate(rand_seeds):
            rand.seed(seed)
            print(seed, end=', ')
            distinct_primes = number_of_distinct_primes(bits)
            for _ in range(tests):
                p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                p_iter = 0
                while p in p_set and len(
                        p_set) < distinct_primes - 1 and p_iter < 10**2:
                    p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                    p_iter += 1
                p_set.add(p)

                bit_seed = rand.randint(1, seed)
                for ind_c, c in enumerate(contests):
                    t = timer()
                    x, iter = pollard_rho(g,
                                          h,
                                          p,
                                          cycle=c[0],
                                          func=c[1],
                                          rand_seed=bit_seed)
                    if x != exp:
                        print("WRONG " + c[0] + " " + c[1])
                    times[ind_b][ind_c][ind_s] += (timer() - t) * 1000
                    iterations[ind_b][ind_c][ind_s] += iter

            for ind_c, c in enumerate(contests):
                iterations[ind_b][ind_c][ind_s] /= tests
                times[ind_b][ind_c][ind_s] /= tests
        print()
        for ind_c, c in enumerate(contests):
            iterations_avg[ind_b][ind_c] = avg(
                iterations[ind_b][ind_c]) / ceil(sqrt(p))
            times_avg[ind_b][ind_c] = avg(times[ind_b][ind_c])
            print(
                f"Cycle: {c[0]}, function: {c[1]}, itertions: {iterations_avg[ind_b][ind_c]:.4f}, time: {times_avg[ind_b][ind_c]:.3f}"
            )
        print()

    plt.figure(0)
    for ind_c, c in enumerate(contests):
        the_times = [t[ind_c] for t in times_avg]
        plt.plot(listOfBits,
                 the_times,
                 marker=next(marker),
                 label=c[0] + '_' + c[1])
    plt.legend()
    plt.ylabel("Milisecunde")
    plt.xlabel("biti")
    # plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
    plt.yscale('log')
    plt.savefig(img_path + '/pollard_time.png', bbox_inches='tight')

    plt.figure(1)
    print("The avg number of iterations: ", end='')
    avgits = []
    for ind_c, c in enumerate(contests):
        the_iterations = [it[ind_c] for it in iterations_avg]
        avg_c = avg(the_iterations)
        print(c[0] + '-' + c[1] + f": {avg_c:.4f}", end=' ')
        avgits.append(avg_c)
        plt.plot(listOfBits,
                 the_iterations,
                 marker=next(marker),
                 label=c[0] + '_' + c[1])
    plt.legend()
    plt.ylabel("Iteratii")
    plt.xlabel("biti")
    # plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
    plt.yscale('log')
    plt.savefig(img_path + '/pollard_iter.png', bbox_inches='tight')
    plt.show()
    return avgits
def test_pollard_dellays(numOfTests: int,
                         listOfBits: list,
                         contests: dict,
                         img_path: str,
                         rand_seeds=[0]):
    iterations = [[[0 for _ in rand_seeds] for _ in contests]
                  for _ in listOfBits]
    iterations_avg = [[0 for _ in contests] for _ in listOfBits]

    lambs = [[[0 for _ in rand_seeds] for _ in contests] for _ in listOfBits]
    lambs_avg = [[0 for _ in contests] for _ in listOfBits]

    mus = [[[0 for _ in rand_seeds] for _ in contests] for _ in listOfBits]
    mus_avg = [[0 for _ in contests] for _ in listOfBits]

    for ind_b, bits in enumerate(listOfBits):
        print("Bits: ", bits)
        tests = num_of_tests(bits, numOfTests)
        print("Nr of tests: ", tests)
        p_set = set()
        print("Seed: ", end='')
        for ind_s, seed in enumerate(rand_seeds):
            rand.seed(seed)
            print(seed, end=', ')
            distinct_primes = number_of_distinct_primes(bits)
            for _ in range(tests):
                p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                p_iter = 0
                while p in p_set and len(
                        p_set) < distinct_primes - 1 and p_iter < 10**2:
                    p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                    p_iter += 1
                p_set.add(p)

                bit_seed = rand.randint(1, seed)
                for ind_c, c in enumerate(contests):
                    x, iter, lamb, mu = pollard_rho(g,
                                                    h,
                                                    p,
                                                    cycle=c[0],
                                                    func=c[1],
                                                    rand_seed=bit_seed)
                    if x != exp:
                        print("WRONG " + c[0] + " " + c[1])
                    iterations[ind_b][ind_c][ind_s] += iter
                    lambs[ind_b][ind_c][ind_s] += lamb
                    mus[ind_b][ind_c][ind_s] += mu

            for ind_c, c in enumerate(contests):
                iterations[ind_b][ind_c][ind_s] /= tests
                lambs[ind_b][ind_c][ind_s] /= tests
                mus[ind_b][ind_c][ind_s] /= tests
        print()
        for ind_c, c in enumerate(contests):
            iterations_avg[ind_b][ind_c] = avg(
                iterations[ind_b][ind_c]) / ceil(sqrt(p))
            lambs_avg[ind_b][ind_c] = avg(lambs[ind_b][ind_c]) / ceil(sqrt(p))
            mus_avg[ind_b][ind_c] = avg(mus[ind_b][ind_c]) / ceil(sqrt(p))
            print(
                f"Cycle: {c[0]}, function: {c[1]}, itertions: {iterations_avg[ind_b][ind_c]:.4f}, lambs: {lambs_avg[ind_b][ind_c]:.4f} mus: {mus_avg[ind_b][ind_c]:.4f}, "
                f"rho: {lambs_avg[ind_b][ind_c] + mus_avg[ind_b][ind_c]:.4f} delay: {iterations_avg[ind_b][ind_c]/(lambs_avg[ind_b][ind_c] + mus_avg[ind_b][ind_c]):.4f}"
            )
        print()

    for ind_c, c in enumerate(contests):
        the_iterations = avg([it[ind_c] for it in iterations_avg])
        the_lambs = [lamb[ind_c] for lamb in lambs_avg]
        the_mus = [mu[ind_c] for mu in mus_avg]
        the_rhos = avg([x + y for x, y in zip(the_lambs, the_mus)])
        print(
            f"Cycle: {c[0]}, function: {c[1]}, itertions_avg: {the_iterations:.4f}, rho: {the_rhos:.4f}, delays {the_iterations/the_rhos:.4f}"
        )
def test_shanks_clasic_inter_grumpy(numOfTests: int,
                                    numOfBits: list,
                                    randSeeds=[0]):
    total_steps_class_list, times_clasic_list, total_memory_clasic = [], [], []
    total_steps_inter_list, times_inter_list, total_memory_inter = [], [], []
    total_steps_grumpy_list, times_grumpy_list, total_memory_grumpy = [], [], []
    for bits in numOfBits:
        seed_steps_class_list, seed_times_clasic_list, seed_total_memory_clasic = [], [], []
        seed_steps_inter_list, seed_times_inter_list, seed_total_memory_inter = [], [], []
        seed_steps_grumpy_list, seed_times_grumpy_list, seed_total_memory_grumpy = [], [], []
        print("Started: ", bits)
        if bits >= 50:
            numOfTests = 50
        elif bits >= 40:
            numOfTests = 100
        elif bits >= 30:
            numOfTests = 500
        for s in randSeeds:
            seed(s)
            time_clas, time_inter, time_grumpy = [], [], []
            steps_clas, steps_inter, steps_grumpy = [], [], []
            mem_clas, mem_inter, mem_grumpy = [], [], []
            for iter in range(numOfTests):
                p, g, exp, h = gnp.logarithm_test_numbers(bits, False)
                t = timer()
                x_c, small_clas, giant_clas, mem_c = shanks_classic(
                    g, h, p, p - 1)
                steps_clas.append(small_clas + giant_clas)
                mem_clas.append(mem_c)
                passed_time = (timer() - t) * 1000
                time_clas.append(passed_time)

                t = timer()
                x_c, oper, mem_c = shanks_interleved(g, h, p, p - 1)
                if x_c != exp:
                    print("NI")
                steps_inter.append(oper)
                mem_inter.append(mem_c)
                passed_time = (timer() - t) * 1000
                time_inter.append(passed_time)

                t = timer()
                x_c, oper, mem_c = shanks_two_grumpys_one_baby(g, h, p, p - 1)
                if x_c != exp:
                    print("NG")
                steps_grumpy.append(oper)
                mem_grumpy.append(mem_c)
                passed_time = (timer() - t) * 1000
                time_grumpy.append(passed_time)
            seed_steps_class_list.append(avg(steps_clas) / ceil(sqrt(p)))
            seed_steps_inter_list.append(avg(steps_inter) / ceil(sqrt(p)))
            seed_steps_grumpy_list.append(avg(steps_grumpy) / ceil(sqrt(p)))
            seed_times_clasic_list.append(avg(time_clas))
            seed_times_inter_list.append(avg(time_inter))
            seed_times_grumpy_list.append(avg(time_grumpy))
            seed_total_memory_clasic.append(avg(mem_clas) / ceil(sqrt(p)))
            seed_total_memory_inter.append(avg(mem_inter) / ceil(sqrt(p)))
            seed_total_memory_grumpy.append(avg(mem_grumpy) / ceil(sqrt(p)))
        print(
            f"Avg steps clasic:{avg(seed_steps_class_list):.4f} -- Avg steps inter:{avg(seed_steps_inter_list):.4f} -- Avg steps grumpy:{avg(seed_steps_grumpy_list):.4f}"
        )
        print(
            f"Avg memory clasic:{avg(seed_total_memory_clasic):.4f} -- Avg memory inter:{avg(seed_total_memory_inter):.4f} -- Avg memory grumpy:{avg(seed_total_memory_grumpy):.4f}"
        )
        print(
            f"Avg time clasic:{avg(seed_times_clasic_list):.4f} -- Avg time inter:{avg(seed_times_inter_list):.4f} -- Avg time grumpy:{avg(seed_times_grumpy_list):.4f}"
        )
        total_steps_class_list.append(avg(seed_steps_class_list))
        total_steps_inter_list.append(avg(seed_steps_inter_list))
        total_steps_grumpy_list.append(avg(seed_steps_grumpy_list))
        times_clasic_list.append(avg(seed_times_clasic_list))
        times_inter_list.append(avg(seed_times_inter_list))
        times_grumpy_list.append(avg(seed_times_grumpy_list))
        total_memory_clasic.append(avg(seed_total_memory_clasic))
        total_memory_inter.append(avg(seed_total_memory_inter))
        total_memory_grumpy.append(avg(seed_total_memory_grumpy))
        print(f"Finished: {bits}\n")

    print(
        f"Avg steps clasic:{avg(total_steps_class_list):.4f} -- Avg steps inter:{avg(total_steps_inter_list):.4f} -- Avg steps grumpy:{avg(total_steps_grumpy_list):.4f}"
    )
    print(
        f"Avg memory clasic:{avg(total_memory_clasic):.4f} -- Avg memory inter:{avg(total_memory_inter):.4f} -- Avg memory grumpy:{avg(total_memory_grumpy):.4f}"
    )
    print(
        f"Avg time clasic:{avg(times_clasic_list):.4f} -- Avg time inter:{avg(times_inter_list):.4f} -- Avg time grumpy:{avg(times_grumpy_list):.4f}"
    )
def L(x):
    x = 2**ceil(log2(x))
    return exp(sqrt(2) * sqrt(log(x) * log(log(x))))