Я могу уменьшить вычислительную сложность этого?

Отказ от ответственности : Я не могу гарантировать, что это 100% правда - ваш вопрос достаточно глубокий, и я могу ошибиться.

1122 Тем не менее, я надеюсь, что это даст вам некоторые мысли или указания.

Давайте рассмотрим этот вопрос в соответствии с CLR организацией памяти:

Локальные переменные метода и параметры метода хранятся в фрейме стека методов в памяти (за исключением того, что они объявлены с ключевым словом ref). [ 1124]

Стек хранит типы значений и ссылки на переменные ссылочного типа, которые указывают на объекты в куче.

Кадр стека метода существует во время выполнения метода, и локальные переменные метода исчезнут вместе с кадром стека после завершения метода.

За исключением случаев, когда локальные переменные были захвачены тем или иным образом, это также относится к работе компилятора , вы можете прочитать об этом на сайте Джона Скита:

http: // jonskeet.uk/csharp/csharp2/delegates.html#captured.variables

Версия 1 : метод OnSomeEvent является членом MyClass и будет захвачен [114 ] до тех пор, пока делегаты, ссылающиеся на этот метод, не будут удалены из события. Таким образом, экземпляр MyClass, созданный в конструкторе, помещенный в кучу и содержащий этот метод, не будет собран GC до тех пор, пока ссылка на его метод не будет удалена из события.

Компилятор компилирует лямбду особым образом, пожалуйста, прочитайте Пример реализации абзац полностью:

https://github.com/dotnet/csharplang/ blob / master / spec / conversions.md # anonymous-function-Conversions

Версия 4 : 2 предоставленные мною ссылки лямбда-импульса будут скомпилированы для метода MyClass, который будет зафиксирован экземпляром SomeClass, как в версии 1

версии 2 : я не знаю нюансов о том, как будут компилироваться локальные методы, но это должно быть таким же, как в версии 4 (и, следовательно, версии 1 ).

Версия 3 : Все локальные переменные будут захвачены интересным способом.

У вас также есть «объект x», поэтому будет создан сгенерированный компилятором класс, который будет содержать открытое поле public object x; и метод, который будет переведен из вашей лямбды (см. пример реализации абзац). [ 1135]

Итак, я думаю, что в версии 1,2,4 будут внутренне одинаковыми: MyClass будет содержать метод, который будет использоваться в качестве обработчика событий.

В версии 3 будет создан сгенерированный компилятором класс, в котором будут храниться ваша локальная переменная и метод, переведенные из lamdba.

Любой экземпляр любого класса не будет собираться GC, пока у события SomeClass не будет свой метод в списке вызовов.

8
задан Charles 16 January 2012 в 19:50
поделиться

10 ответов

Базирующийся от второго редактирования OP:

def table(n):
    if n == 2: return 1
    if n%4 != 1: return

    mod = 0
    a1 = n - 1
    for a in xrange(1, a1, 2):
        mod += a

        while mod >= n: mod -= n
        if mod == a1: return a//2 + 1
2
ответ дан 5 December 2019 в 06:10
поделиться

Смотрите на http://modular.fas.harvard.edu/ent/ent_py. Функция sqrtmod делает задание, если Вы устанавливаете =-1 и p = n.

Маленькая суть, которую Вы упустили, - то, что время выполнения Вашего улучшенного алгоритма находится все еще в порядке квадратного корня n. Поскольку долго у Вас есть только маленькие начала n (скажем, меньше, чем 2^64), это в порядке, и необходимо, вероятно, предпочесть реализацию более сложной.

Если главный n становится больше, Вам, возможно, придется переключиться на алгоритм с помощью определенной теории чисел. К моему знанию Ваша проблема может быть решена только с вероятностным алгоритмом в хронологическом журнале (n) ^3. Если я помню правильно, предполагая, что Riemann гипотеза содержит (который большинство людей делает), можно показать, что время выполнения следующего алгоритма (в рубине - извините, я не знаю, Python) журнал (журнал (n)) *log (n) ^3:

class Integer
  # calculate b to the power of e modulo self
  def power(b, e)
    raise 'power only defined for integer base' unless b.is_a? Integer
    raise 'power only defined for integer exponent' unless e.is_a? Integer
    raise 'power is implemented only for positive exponent' if e < 0
    return 1 if e.zero?
    x = power(b, e>>1)
    x *= x
    (e & 1).zero? ? x % self : (x*b) % self
  end
  # Fermat test (probabilistic prime number test)
  def prime?(b = 2)
    raise "base must be at least 2 in prime?" if b < 2
    raise "base must be an integer in prime?" unless b.is_a? Integer
    power(b, self >> 1) == 1
  end
  # find square root of -1 modulo prime
  def sqrt_of_minus_one
    return 1 if self == 2
    return false if (self & 3) != 1
    raise 'sqrt_of_minus_one works only for primes' unless prime?
    # now just try all numbers (each succeeds with probability 1/2)
    2.upto(self) do |b|
      e = self >> 1
      e >>= 1 while (e & 1).zero?
      x = power(b, e)
      next if [1, self-1].include? x
      loop do
        y = (x*x) % self
        return x if y == self-1
        raise 'sqrt_of_minus_one works only for primes' if y == 1
        x = y
      end
    end
  end
end

# find a prime
p = loop do
      x = rand(1<<512)
      next if (x & 3) != 1
      break x if x.prime?
    end

puts "%x" % p
puts "%x" % p.sqrt_of_minus_one

Медленная часть теперь находит начало (который берет приблизительно журнал (n) ^4 целочисленная операция); нахождение квадратного корня-1 берет для 512-разрядных начал еще меньше, чем секунда.

5
ответ дан 5 December 2019 в 06:10
поделиться

Игнорируя алгоритм на мгновение (да, я знаю, плохая идея), время выполнения этого может быть уменьшено чрезвычайно только путем переключения от while кому: for.

for a in range(1, n / 2 + 1)

(Надежда это не имеет ошибки диапазона. Я являюсь склонным для создания их.)

Другая вещь, которую я попробовал бы, состоит в том, чтобы посмотреть, если ширина шага может быть увеличена.

6
ответ дан 5 December 2019 в 06:10
поделиться

Рассмотрите предварительные вычисления результатов и хранение их в файле. В наше время много платформ имеют огромную емкость диска. Затем получение результата будет O (1) операция.

4
ответ дан 5 December 2019 в 06:10
поделиться

(Построение на ответе Adam.) Смотрят на страницу Wikipedia на квадратичной взаимности:

x^2 ≡ −1 (модификация p) разрешим если и только если p ≡ 1 (модификация 4).

Затем можно избежать поиска корня точно для тех нечетный главный n's, которые не являются конгруэнтными с 1 4 по модулю:

def table(n):
    if n == 2: return 1
    if n%4 != 1: return None   # or raise exception
    ...
3
ответ дан 5 December 2019 в 06:10
поделиться

Похоже, что Вы пытаетесь найти квадратный корень-1 по модулю n. К сожалению, это не легкая проблема, в зависимости от какой значения n вводятся в Вашу функцию. В зависимости от n, даже не могло бы быть решения. Посмотрите Википедию для получения дополнительной информации об этой проблеме.

2
ответ дан 5 December 2019 в 06:10
поделиться

Для Вас действительно ли возможно кэшировать результаты?

При вычислении большого n, Вам дают результаты для более низкого n's почти бесплатно.

1
ответ дан 5 December 2019 в 06:10
поделиться

Редактирование 2: Удивительно, сокращение силы обработка на квадрат уменьшает время много, по крайней мере, на моей установке Python2.5. (Я удивлен, потому что я думал, что интерпретатор наверху брал большую часть времени, и это не уменьшает количество операций во внутреннем цикле.) Уменьшает время с 0,572 с до 0,146 с для таблицы (1234577).

 def table(n):
     n1 = n - 1
     square = 0
     for delta in xrange(1, n, 2):
         square += delta
         if n <= square: square -= n
         if square == n1: return delta // 2 + 1

strager отправил ту же идею, но я думаю менее плотно кодированный. Снова, ответ кувшина является лучшим.

Исходный ответ: Другое тривиальное кодирование настраивает сверху Konrad Rudolph:

def table(n):
    n1 = n - 1
    for a in xrange(1, n // 2 + 1):
          if (a*a) % n == n1: return a

Ускоряет его в известной мере на моем ноутбуке. (Приблизительно 25% для таблицы (1234577).)

Править: Я не заметил тега python3.0; но основное изменение поднимало часть вычисления из цикла, не использования xrange. (Академический с тех пор существует лучший алгоритм.)

2
ответ дан 5 December 2019 в 06:10
поделиться

Одна вещь, которую Вы делаете, повторяет вычисление-a*a много раз.

Составьте таблицу значений однажды и затем ищите в основном цикле.

Также, хотя это, вероятно, не относится к Вам, потому что Ваше имя функции является таблицей, но если Вы вызываете функцию, которая занимает время для вычисления, необходимо кэшировать результат в таблице и просто привести в порядок, таблица смотрит при вызове его снова с тем же значением. Это экономит Вам время вычисления всех значений, когда Вы первый показ, но Вы не напрасно тратите время, повторяя вычисление несколько раз.

1
ответ дан 5 December 2019 в 06:10
поделиться

Я прошел и зафиксировал версию Гарварда, чтобы заставить его работать с python 3. http://modular.fas.harvard.edu/ent/ent_py

Я внес некоторые небольшие изменения для создания результатов точно тем же как функция OP. Существует два возможных ответа, и я вынудил это дать меньший ответ.

import timeit

def table(n):

    if n == 2: return 1
    if n%4 != 1: return

    a1=n-1

    def inversemod(a, p):
        x, y = xgcd(a, p)
        return x%p

    def xgcd(a, b):
        x_sign = 1
        if a < 0: a = -a; x_sign = -1
        x = 1; y = 0; r = 0; s = 1
        while b != 0:
            (c, q) = (a%b, a//b)
            (a, b, r, s, x, y) = (b, c, x-q*r, y-q*s, r, s)
        return (x*x_sign, y)

    def mul(x, y):      
        return ((x[0]*y[0]+a1*y[1]*x[1])%n,(x[0]*y[1]+x[1]*y[0])%n)

    def pow(x, nn):      
        ans = (1,0)
        xpow = x
        while nn != 0:
           if nn%2 != 0:
               ans = mul(ans, xpow)
           xpow = mul(xpow, xpow)
           nn >>= 1
        return ans

    for z in range(2,n) :
        u, v = pow((1,z), a1//2)
        if v != 0:
            vinv = inversemod(v, n)
            if (vinv*vinv)%n == a1:
                vinv %= n
                if vinv <= n//2:
                    return vinv
                else:
                    return n-vinv


tt=0
pri = [ 5,13,17,29,37,41,53,61,73,89,97,1234577,5915587277,3267000013,3628273133,2860486313,5463458053,3367900313 ]
for x in pri:
    t=timeit.Timer('q=table('+str(x)+')','from __main__ import table')
    tt +=t.timeit(number=100)
    print("table(",x,")=",table(x))

print('total time=',tt/100)

Эта версия берет приблизительно 3 мс для пробежки тестовых сценариев выше.

Для сравнения с помощью простого числа 1234577
OP Edit2 745 мс
Принятый ответ 522 мс
Вышеупомянутая функция 0,2 мс

1
ответ дан 5 December 2019 в 06:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: