为什么在访问单个数字时,大整数除法比切片(数字)字符串更快?

发布于 2024-12-05 09:09:58 字数 840 浏览 2 评论 0原文

我正在做一项(典型的)寻找素数的作业。我认为我会很聪明,对于大数,用这个技巧跳过除法过程:

def div5(candidate):
    return str(candidate)[-1] == "5"

将 5 添加到自身几千次似乎是一种浪费(我只需要最后一个成员),但我想确定一下。

归功于unutbu Measure time elapsed in Python?

%>python -mtimeit -s"import intDiv" "intDiv.div5(2147483645)"
1000000 loops, best of 3: 0.272 usec per loop

%>python -mtimeit -s"import strDiv" "strDiv.str5(2147483645)"
1000000 loops, best of 3: 0.582 usec per loop

澄清一下,这是我定义的两个方法。

def div5(maxi): return not (maxi%5)

def str5(maxi): return str(maxi)[-1] == '5'

这太慢了。如何分析 str(maxi) 的最后一个成员,而不转换整个数字(不必要)?

感谢 @Claudiu 帮助清理了那些碍眼的东西。

I am doing a (typical) assignment of finding primes. I thought I'd be clever and, for large numbers, skip the division process with this trick:

def div5(candidate):
    return str(candidate)[-1] == "5"

Adding 5 to itself a few thousand times seems like a waste (I only need the last member), but I wanted to be sure.

credit to unutbu on Measure time elapsed in Python?

%>python -mtimeit -s"import intDiv" "intDiv.div5(2147483645)"
1000000 loops, best of 3: 0.272 usec per loop

%>python -mtimeit -s"import strDiv" "strDiv.str5(2147483645)"
1000000 loops, best of 3: 0.582 usec per loop

For clarification, here are the two methods I defined.

def div5(maxi): return not (maxi%5)

def str5(maxi): return str(maxi)[-1] == '5'

This is too slow. How can I analyze the last member of str(maxi), without converting the whole number (needlessly)?

Thanks to @Claudiu for help with cleaning up the eyesores.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

酒儿 2024-12-12 09:09:58
% python -mtimeit "str(2147483645)"
1000000 loops, best of 3: 0.321 usec per loop

% python -mtimeit "2147483645 % 5"
10000000 loops, best of 3: 0.0351 usec per loop

% python -mtimeit "'2147483645'[-1]"
10000000 loops, best of 3: 0.0349 usec per loop

我想说瓶颈在于转换为字符串。

% python -mtimeit "str(2147483645)"
1000000 loops, best of 3: 0.321 usec per loop

% python -mtimeit "2147483645 % 5"
10000000 loops, best of 3: 0.0351 usec per loop

% python -mtimeit "'2147483645'[-1]"
10000000 loops, best of 3: 0.0349 usec per loop

I'd say the bottleneck is converting to a string.

不必了 2024-12-12 09:09:58

一个问题是将整数转换为字符串。这比整数除法要工作得多。
我不确定Python是如何做到这一点的,但大多数算法的工作原理都是这样的

def tostring(value):
    result = ""
    while True:
        digit = value % 10
        value = value / 10
        result = chr(digit + ord('0')) + result
        if value == 0: break

    return result

,即每个有多个模运算。

One problem is the conversion of an integer to a string. This is much more work than doing integer division.
I am not sure how Python does it, but most algorithms work like

def tostring(value):
    result = ""
    while True:
        digit = value % 10
        value = value / 10
        result = chr(digit + ord('0')) + result
        if value == 0: break

    return result

That is you have more than one modulo operation per value.

梦里兽 2024-12-12 09:09:58

将数字转换为字符串将如下所示:

digits = []
while x:
    digits.append(x % 10)
    x //= 10

您可以看到这将执行大量 % 操作(除了构建数字或字符串列表之外)。

除了这个优化问题之外,您的函数不正确。例如,10 不以 5 结尾,但可以被 5 整除。

Converting the number to a string will look something like this:

digits = []
while x:
    digits.append(x % 10)
    x //= 10

You can see this is going to do lots of % operations (aside from the construction of the list of digits or string).

Apart from this optimisation problem, your function isn't correct. For example, 10 doesn't end with 5, yet is divisible by 5.

薄荷港 2024-12-12 09:09:58

您需要检查 5 和 0 是否能被 5 整除:

def str5(candidate):
    return str(candidate)[-1] in ["5","0"]

使用 6k±1 怎么样。如果该数字不能是素数,则返回 False。 2147483645%6 = 5 因此它可能是素数并且需要检查。此代码的运行时间比 div5 检查稍长一些,但您可以确定数字是否不能是素数。 3 以上的所有素数都符合序列 6k±1。所以 6(1)±1 = (5,7) 6(3)±1 = (17,19) 等等。模 6 都返回 5 或 1 作为余数。

def is6k(candidate):
    if candidate<=3: return candidate>1
    if candidate%5==0: return False
    return candidate%6 in [1,5]

我的 isPrime 适合小于 10**15 的数字。它还仅检查 sqrt(n) 并仅除以可能的素数。 for 循环将 p 和 q 设置为 5,7 11,13 17,19 23,25 29,31...

def isPrime(n):  
    if (n <= 3): return n > 1      
    if n%6 not in [1,5]: return False      
    for p,q in ((i,i+2) for i in range(5,int(n**.5)+1,6)): 
        if (n%p == 0 or n%q == 0):  return False          
    return True  

时间:

$ python -mtimeit -s"import prime" "prime.div5(2147483645)"
1000000 loops, best of 5: 145 nsec per loop


$ python -mtimeit -s"import prime" "prime.is6k(2147483645)"
1000000 loops, best of 5: 210 nsec per loop

整个素数测试需要更长的时间:

$ python -mtimeit -s"import prime" "prime.isPrime(2147483645)"
100000 loops, best of 5: 1.96 usec per loop

You need to check 5 and 0 for divisible by 5:

def str5(candidate):
    return str(candidate)[-1] in ["5","0"]

How about using 6k±1. Return False if the number can't be a prime. 2147483645%6 = 5 so it could be prime and needs to be checked. This code runs for a little bit longer than the div5 check but you know for sure if a number cannot be prime. All primes above 3 fit into the sequence 6k±1. So 6(1)±1 = (5,7) 6(3)±1 = (17,19) and so on. modulus 6 all return either 5 or 1 as the remainder.

def is6k(candidate):
    if candidate<=3: return candidate>1
    if candidate%5==0: return False
    return candidate%6 in [1,5]

My isPrime for numbers less than 10**15. It also only checks up to sqrt(n) and only divides by possible primes. The for loop sets p and q to 5,7 11,13 17,19 23,25 29,31...

def isPrime(n):  
    if (n <= 3): return n > 1      
    if n%6 not in [1,5]: return False      
    for p,q in ((i,i+2) for i in range(5,int(n**.5)+1,6)): 
        if (n%p == 0 or n%q == 0):  return False          
    return True  

Times:

$ python -mtimeit -s"import prime" "prime.div5(2147483645)"
1000000 loops, best of 5: 145 nsec per loop


$ python -mtimeit -s"import prime" "prime.is6k(2147483645)"
1000000 loops, best of 5: 210 nsec per loop

The whole prime test takes a bit longer:

$ python -mtimeit -s"import prime" "prime.isPrime(2147483645)"
100000 loops, best of 5: 1.96 usec per loop
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文