我可以降低这个的计算复杂度吗?
好吧,我的这段代码极大地减慢了程序的速度,因为它是线性复杂性的,但被调用了很多次,使得程序的复杂性变成了二次方。 如果可能的话,我想降低其计算复杂性,但否则我会尽可能优化它。 到目前为止,我已经简化为:
def table(n):
a = 1
while 2*a <= n:
if (-a*a)%n == 1: return a
a += 1
有人看到我错过的任何东西吗? 谢谢!
编辑:我忘了提及:n 始终是质数。
编辑 2:这是我新改进的程序(感谢所有贡献!):
def table(n):
if n == 2: return 1
if n%4 != 1: return
a1 = n-1
for a in range(1, n//2+1):
if (a*a)%n == a1: return a
编辑 3:在真实环境中测试它,它快得多! 嗯,这个问题似乎已经解决了,但有很多有用的答案。 我还应该说,除了上述优化之外,我还使用 Python 字典记住了该函数......
Well, I have this bit of code that is slowing down the program hugely because it is linear complexity but called a lot of times making the program quadratic complexity. If possible I would like to reduce its computational complexity but otherwise I'll just optimize it where I can. So far I have reduced down to:
def table(n):
a = 1
while 2*a <= n:
if (-a*a)%n == 1: return a
a += 1
Anyone see anything I've missed? Thanks!
EDIT: I forgot to mention: n is always a prime number.
EDIT 2: Here is my new improved program (thank's for all the contributions!):
def table(n):
if n == 2: return 1
if n%4 != 1: return
a1 = n-1
for a in range(1, n//2+1):
if (a*a)%n == a1: return a
EDIT 3: And testing it out in its real context it is much faster! Well this question appears solved but there are many useful answers. I should also say that as well as those above optimizations, I have memoized the function using Python dictionaries...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
您正在做的一件事是一遍又一遍地重复计算 -a*a 。
创建一个值表一次,然后在主循环中查找。
另外,虽然这可能不适用于您,因为您的函数名称是表,但如果您调用一个需要时间来计算的函数,您应该将结果缓存在表中,并且如果您使用相同的名称再次调用它,则只需进行表查找价值。 这可以节省您首次运行时计算所有值的时间,但您不会浪费时间多次重复计算。
One thing that you are doing is repeating the calculation -a*a over and over again.
Create a table of the values once and then do look up in the main loop.
Also although this probably doesn't apply to you because your function name is table but if you call a function that takes time to calculate you should cache the result in a table and just do a table look up if you call it again with the same value. This save you the time of calculating all of the values when you first run but you don't waste time repeating the calculation more than once.
我检查并修复了哈佛版本,使其可以与 python 3 一起使用。
http://modular.fas.harvard.edu/ent/ent_py
我做了一些稍微改变一下,使结果与OP的功能完全相同。 有两个可能的答案,我强迫它返回较小的答案。
该版本运行上述测试用例大约需要 3 毫秒。
使用质数 1234577 进行比较
OP Edit2 745ms
接受的答案 522ms
上述函数0.2ms
I went through and fixed the Harvard version to make it work with python 3.
http://modular.fas.harvard.edu/ent/ent_py
I made some slight changes to make the results exactly the same as the OP's function. There are two possible answers and I forced it to return the smaller answer.
This version takes about 3ms to run through the test cases above.
For comparison using the prime number 1234577
OP Edit2 745ms
The accepted answer 522ms
The above function 0.2ms
暂时忽略算法(是的,我知道,坏主意),只需从
while
切换到for< /代码>。
(希望这不会出现相差一的错误。我很容易犯这些错误。)
我会尝试的另一件事是看看步长是否可以增加。
Ignoring the algorithm for a moment (yes, I know, bad idea), the running time of this can be decreased hugely just by switching from
while
tofor
.(Hope this doesn't have an off-by-one error. I'm prone to make these.)
Another thing that I would try is to look if the step width can be incremented.
看看http://modular.fas.harvard.edu/ent/ent_py .
如果设置 a = -1 且 p = n,则函数 sqrtmod 即可完成这项工作。
你错过了一个小点,因为你的改进算法的运行时间仍然是n的平方根的数量级。 只要您只有小素数 n(比方说小于 2^64),就可以了,并且您可能应该更喜欢您的实现而不是更复杂的实现。
如果素数 n 变得更大,您可能必须切换到使用一点数论的算法。 据我所知,您的问题只能在时间 log(n)^3 内使用概率算法来解决。 如果我没记错的话,假设黎曼假设成立(大多数人都是这样做的),可以证明以下算法的运行时间(在 ruby 中 - 抱歉,我不知道 python)是 log(log(n))* log(n)^3:
缓慢的部分现在正在寻找素数(大约需要 log(n)^4 整数运算); 对于 512 位素数求 -1 的平方根仍然需要不到一秒的时间。
Take a look at http://modular.fas.harvard.edu/ent/ent_py .
The function sqrtmod does the job if you set a = -1 and p = n.
You missed a small point because the running time of your improved algorithm is still in the order of the square root of n. As long you have only small primes n (let's say less than 2^64), that's ok, and you should probably prefer your implementation to a more complex one.
If the prime n becomes bigger, you might have to switch to an algorithm using a little bit of number theory. To my knowledge, your problem can be solved only with a probabilistic algorithm in time log(n)^3. If I remember correctly, assuming the Riemann hypothesis holds (which most people do), one can show that the running time of the following algorithm (in ruby - sorry, I don't know python) is log(log(n))*log(n)^3:
The slow part is now finding the prime (which takes approx. log(n)^4 integer operation); finding the square root of -1 takes for 512-bit primes still less than a second.
考虑预先计算结果并将其存储在文件中。 现在许多平台都拥有巨大的磁盘容量。 然后,获得结果将是一个 O(1) 的操作。
Consider pre-computing the results and storing them in a file. Nowadays many platforms have a huge disk capacity. Then, obtaining the result will be an O(1) operation.
(以亚当的回答为基础。)
查看关于二次互易的维基百科页面:
然后,您可以避免精确搜索那些与 1 模 4 不全等的奇素数 n 的根:
(Building on Adam's answer.)
Look at the Wikipedia page on quadratic reciprocity:
Then you can avoid the search of a root precisely for those odd prime n's that are not congruent with 1 modulo 4:
基于OP的第二次编辑:
Based off OP's second edit:
看起来您正在尝试求 -1 模
n
的平方根。 不幸的是,这不是一个简单的问题,具体取决于您的函数中输入的n
值。 根据n
,甚至可能没有解决方案。 有关此问题的更多信息,请参阅维基百科。It looks like you're trying to find the square root of -1 modulo
n
. Unfortunately, this is not an easy problem, depending on what values ofn
are input into your function. Depending onn
, there might not even be a solution. See Wikipedia for more information on this problem.编辑2:令人惊讶的是,减少平方强度大大减少了时间,至少在我的Python2.5安装上是这样。 (我很惊讶,因为我认为解释器开销占用了大部分时间,并且这并没有减少内部循环中的操作数量。)将表(1234577)的时间从 0.572 秒减少到 0.146 秒。
strager 发布了同样的想法,但我认为不太严格编码。 同样,jug 的答案是最好的。
原始答案:在康拉德·鲁道夫的基础上进行的另一个简单的编码调整:
在我的笔记本电脑上显着加快速度。 (表(1234577)大约占 25%。)
编辑:我没有注意到 python3.0 标签; 但主要的变化是将部分计算提升到循环之外,而不是使用 xrange。 (学术性的,因为有更好的算法。)
Edit 2: Surprisingly, strength-reducing the squaring reduces the time a lot, at least on my Python2.5 installation. (I'm surprised because I thought interpreter overhead was taking most of the time, and this doesn't reduce the count of operations in the inner loop.) Reduces the time from 0.572s to 0.146s for table(1234577).
strager posted the same idea but I think less tightly coded. Again, jug's answer is best.
Original answer: Another trivial coding tweak on top of Konrad Rudolph's:
Speeds it up measurably on my laptop. (About 25% for table(1234577).)
Edit: I didn't notice the python3.0 tag; but the main change was hoisting part of the calculation out of the loop, not the use of
xrange
. (Academic since there's a better algorithm.)你可以缓存结果吗?
当你计算一个大的 n 时,你几乎可以免费得到较小的 n 的结果。
Is it possible for you to cache the results?
When you calculate a large n you are given the results for the lower n's almost for free.