在python/pypy中优化暴力进程以查找一个子编号

在python/pypy中优化暴力进程以查找一个子编号,python,optimization,multiprocessing,brute-force,pypy,Python,Optimization,Multiprocessing,Brute Force,Pypy,蛮力方法的目的不是解决问题,而是帮助研究。我正在研究一个问题,它让我找到从X到小于Y的所有数字,这些数字正好有一个“子串”,可以被数字中的位数整除 这些被称为独生子女号码。104是一个独生子女号码。在它的子串中,[1,0,4,10,04,104]只有0可以被3整除。这个问题要求找出小于10*17的独生子女数量。暴力手段不是正确的方法;然而,我有一个理论,要求我知道10*11之前发生的独生子女数量 即使我的笔记本电脑开了半天,我也没有成功地找到这个号码。我试过Cython,我是一个对C一无所知的新

蛮力方法的目的不是解决问题,而是帮助研究。我正在研究一个问题,它让我找到从X到小于Y的所有数字,这些数字正好有一个“子串”,可以被数字中的位数整除

这些被称为独生子女号码。104是一个独生子女号码。在它的子串中,[1,0,4,10,04,104]只有0可以被3整除。这个问题要求找出小于10*17的独生子女数量。暴力手段不是正确的方法;然而,我有一个理论,要求我知道10*11之前发生的独生子女数量

即使我的笔记本电脑开了半天,我也没有成功地找到这个号码。我试过Cython,我是一个对C一无所知的新手程序员。结果很糟糕。我甚至尝试过云计算,但我的ssh管道总是在过程完成之前中断

如果有人能帮我找出一些不同的方法或优化来进行暴力 对于10**11以上的问题,我们将不胜感激

请不要

请给我一些关于数论的建议或者你对这个问题的答案,因为我已经研究了很长时间了,我真的很想自己得出结论

## a one child number has only one "substring" divisable by the
## number of digits in the number. Example: 104 is a one child number as 0
## is the only substring which 3 may divide, of the set [1,0,4,10,04,104]

## FYI one-child numbers are positive, so the number 0 is not one-child


from multiprocessing import Pool
import os.path

def OneChild(numRange): # hopefully(10*11,1)
    OneChild = []
    start = numRange[0]
    number = numRange[1]

    ## top loop handles one number at a time
    ## loop ends when start become larger then end
    while number >= start:

        ## preparing to analayze one number
        ## for exactly one divisableSubstrings
        numberString = str(start)
        numDigits = len(numberString)
        divisableSubstrings = 0
        ticker1,ticker2 = 0, numDigits

        ## ticker1 starts at 0 and ends at number of digits - 1
        ## ticker2 starts at number of digits and ends +1 from ticker1
        ## an example for a three digit number: (0,3) (0,2) (0,1) (1,3) (1,2) (2,3)
        while ticker1 <= numDigits+1:
            while ticker2 > ticker1:
                if int(numberString[ticker1:ticker2]) % numDigits == 0:
                    divisableSubstrings += 1
                    if divisableSubstrings == 2:
                        ticker1 = numDigits+1
                        ticker2 = ticker1

                ##Counters    
                ticker2 -= 1
            ticker1 += 1
            ticker2 = numDigits             
        if divisableSubstrings == 1: ## One-Child Bouncer 
            OneChild.append(start) ## inefficient but I want the specifics
        start += 1 
    return (OneChild)

## Speed seems improve with more pool arguments, labeled here as cores
## Im guessing this is due to pypy preforming best when task is neither
## to large nor small
def MultiProcList(numRange,start = 1,cores = 100): # multiprocessing
    print "Asked to use %i cores between %i numbers: From %s to %s" % (cores,numRange-start, start,numRange)
    cores = adjustCores(numRange,start,cores)
    print "Using %i cores" % (cores)

    chunk = (numRange+1-start)/cores
    end = chunk+start -1 
    total, argsList= 0, []
    for i in range(cores):
        # print start,end-1
        argsList.append((start,end-1))
        start, end = end , end + chunk
    pool = Pool(processes=cores)
    data = pool.map(OneChild,argsList)
    for d in data:
        total += len(d)
    print total

##    f = open("Result.txt", "w+")
##    f.write(str(total))
##    f.close()

def adjustCores(numRange,start,cores):
    if start == 1:
        start = 0
    else:
        pass
    while (numRange-start)%cores != 0:
        cores -= 1
    return cores

#MultiProcList(10**7)
from timeit import Timer
t = Timer(lambda: MultiProcList(10**6))
print t.timeit(number=1)
##一个子编号只有一个“子字符串”,可被
##数字中的位数。示例:104是作为0的一个子编号
##是集合[1,0,4,10,04104]中3可以分割的唯一子串
##仅供参考,独生子女数为正数,因此数字0不是独生子女
来自多处理导入池
导入操作系统路径
def OneChild(numRange):#希望(10*11,1)
一个孩子=[]
开始=numRange[0]
数字=numRange[1]
##顶部循环一次处理一个数字
##循环在“开始”变大“结束”时结束
当数字>=开始时:
##准备分析一个数字
##对于正好一个可除子串
numberString=str(开始)
numDigits=len(numberString)
可除子字符串=0
ticker1,ticker2=0,numDigits
##ticker1从0开始,在位数-1结束
##ticker2从数字开始,从ticker1到+1结束
##一个三位数的例子:(0,3)(0,2)(0,1)(1,3)(1,2)(2,3)
而ticker1 ticker1:
如果int(numberString[ticker1:ticker2])%numDigits==0:
可除子串+=1
如果可除子字符串==2:
ticker1=numDigits+1
ticker2=ticker1
##计数器
ticker2-=1
ticker1+=1
ticker2=numDigits
如果可除子字符串==1:##一个子保镖
OneChild.append(start)##效率低下,但我需要详细信息
开始+=1
报税表(一名子女)
##速度似乎随着更多池参数(此处标记为核心)的增加而提高
##我猜这是因为pypy在任务既不是
##大大小小
def多进程列表(numRange,start=1,cores=100):#多进程
打印“要求在%i个数字之间使用%i个核:从%s到%s”%(核,numRange开始,开始,numRange)
核心=调整核心(numRange、start、cores)
打印“使用%i个核心”%(核心)
块=(numRange+1-start)/核心
结束=块+开始-1
总计,argsList=0,[]
对于范围内的i(芯):
#打印开始,结束-1
argsList.append((开始,结束-1))
开始,结束=结束,结束+区块
池=池(进程=核心)
data=pool.map(OneChild,argsList)
对于数据中的d:
总数+=len(d)
打印总数
##f=打开(“Result.txt”,“w+”)
##f.写入(str(总计))
##f.关闭()
def调整旧件(numRange、start、旧件):
如果start==1:
开始=0
其他:
通过
while(numRange start)%cores!=0:
芯数-=1
返回磁芯
#多进程列表(10**7)
从timeit导入计时器
t=定时器(λ:多进程列表(10**6))
打印t.timeit(数字=1)

这是我最快的暴力代码。它使用cython来加速计算。它不是检查所有的数字,而是通过递归查找所有的一个子数字

%%cython
cdef int _one_child_number(int s, int child_count, int digits_count):
    cdef int start, count, c, child_count2, s2, part, i
    if s >= 10**(digits_count-1):
        return child_count
    else:
        if s == 0:
            start = 1
        else:
            start = 0
        count = 0
        for c in range(start, 10):
            s2 = s*10 + c
            child_count2 = child_count
            i = 10
            while True:
                part = s2 % i
                if part % digits_count == 0:
                    child_count2 += 1
                    if child_count2 > 1:
                        break
                if part == s2:
                    break
                i *= 10

            if child_count2 <= 1:
                count += _one_child_number(s2, child_count2, digits_count)
        return count 

def one_child_number(int digits_count):
    return _one_child_number(0, 0, digits_count)
您需要64位整数来计算较大的结果。

编辑:我添加了一些注释,但我的英语不好,所以我将代码转换为纯python代码,并添加一些打印以帮助您了解其工作原理

\u one\u child\u number
递归地从左到
s添加数字,
child\u count
s
中的子计数,
digits\u count
s
的最后数字

def _one_child_number(s, child_count, digits_count):
    print s, child_count
    if s >= 10**(digits_count-1): # if the length of s is digits_count
        return child_count # child_count is 0 or 1 here, 1 means we found one one-child-number.
    else:
        if s == 0: 
            start = 1 #if the length of s is 0, we choose from 123456789 for the most left digit.
        else:
            start = 0 #otherwise we choose from 0123456789 
        count = 0 # init the one-child-number count
        for c in range(start, 10): # loop for every digit
            s2 = s*10 + c  # add digit c to the right of s

            # following code calculates the child count of s2
            child_count2 = child_count 
            i = 10
            while True:
                part = s2 % i
                if part % digits_count == 0:
                    child_count2 += 1
                    if child_count2 > 1: # when child count > 1, it's not a one-child-number, break
                        break
                if part == s2:
                    break
                i *= 10

            # if the child count by far is less than or equal 1, 
            # call _one_child_number recursively to add next digit.
            if child_count2 <= 1: 
                count += _one_child_number(s2, child_count2, digits_count)
        return count 

你为什么要使用蛮力方法?他只对问题的一小部分使用蛮力,然后用数论来解决实际问题。我能想出的最有效的方法需要15秒才能通过10**7,即使是PyPy。我真的很怀疑有没有一种方法可以强制执行。你有没有通过任何测试软件来运行它,看看什么占用了最多的时间?VisualStudio从memory@maxk是完全正确的。10i(i是素数)的解具有较大的素数因子,如果pi()是预生成的,则会导致较小的素数。10i=[2,3,5,7]的除数依次需要+1π运算才能达到非素数。这些非素数也有一个基本的顺序。问题是7和5是唯一的数字,它们奇怪的素数设计比解小。我怀疑2和5不会给我我想要的信息,因为它们平均地除以10。第三个素数不能除十,这会让事情变得更清楚。请!因为这个程序是递归的,所以print语句和嵌套print语句不能有效地传递代码背后的魔力。我
def _one_child_number(s, child_count, digits_count):
    print s, child_count
    if s >= 10**(digits_count-1): # if the length of s is digits_count
        return child_count # child_count is 0 or 1 here, 1 means we found one one-child-number.
    else:
        if s == 0: 
            start = 1 #if the length of s is 0, we choose from 123456789 for the most left digit.
        else:
            start = 0 #otherwise we choose from 0123456789 
        count = 0 # init the one-child-number count
        for c in range(start, 10): # loop for every digit
            s2 = s*10 + c  # add digit c to the right of s

            # following code calculates the child count of s2
            child_count2 = child_count 
            i = 10
            while True:
                part = s2 % i
                if part % digits_count == 0:
                    child_count2 += 1
                    if child_count2 > 1: # when child count > 1, it's not a one-child-number, break
                        break
                if part == s2:
                    break
                i *= 10

            # if the child count by far is less than or equal 1, 
            # call _one_child_number recursively to add next digit.
            if child_count2 <= 1: 
                count += _one_child_number(s2, child_count2, digits_count)
        return count 
0 0
1 0
10 1
101 1
104 1
107 1
11 0
110 1
111 1
112 1
113 1
114 1
115 1
116 1
117 1
118 1
119 1
12 1
122 1
125 1
128 1
13 1
131 1
134 1
137 1
14 0
140 1
141 1
142 1
143 1
144 1
145 1
146 1
147 1
148 1
149 1
15 1
152 1
155 1
158 1
16 1
161 1
164 1
167 1
17 0
170 1
171 1
172 1
173 1
174 1
175 1
176 1
177 1
178 1
179 1
18 1
182 1
185 1
188 1
19 1
191 1
194 1
197 1
2 0
20 1
202 1
205 1
208 1
21 1
211 1
214 1
217 1
22 0
220 1
221 1
222 1
223 1
224 1
225 1
226 1
227 1
228 1
229 1
23 1
232 1
235 1
238 1
24 1
241 1
244 1
247 1
25 0
250 1
251 1
252 1
253 1
254 1
255 1
256 1
257 1
258 1
259 1
26 1
262 1
265 1
268 1
27 1
271 1
274 1
277 1
28 0
280 1
281 1
282 1
283 1
284 1
285 1
286 1
287 1
288 1
289 1
29 1
292 1
295 1
298 1
3 1
31 1
311 1
314 1
317 1
32 1
322 1
325 1
328 1
34 1
341 1
344 1
347 1
35 1
352 1
355 1
358 1
37 1
371 1
374 1
377 1
38 1
382 1
385 1
388 1
4 0
40 1
401 1
404 1
407 1
41 0
410 1
411 1
412 1
413 1
414 1
415 1
416 1
417 1
418 1
419 1
42 1
422 1
425 1
428 1
43 1
431 1
434 1
437 1
44 0
440 1
441 1
442 1
443 1
444 1
445 1
446 1
447 1
448 1
449 1
45 1
452 1
455 1
458 1
46 1
461 1
464 1
467 1
47 0
470 1
471 1
472 1
473 1
474 1
475 1
476 1
477 1
478 1
479 1
48 1
482 1
485 1
488 1
49 1
491 1
494 1
497 1
5 0
50 1
502 1
505 1
508 1
51 1
511 1
514 1
517 1
52 0
520 1
521 1
522 1
523 1
524 1
525 1
526 1
527 1
528 1
529 1
53 1
532 1
535 1
538 1
54 1
541 1
544 1
547 1
55 0
550 1
551 1
552 1
553 1
554 1
555 1
556 1
557 1
558 1
559 1
56 1
562 1
565 1
568 1
57 1
571 1
574 1
577 1
58 0
580 1
581 1
582 1
583 1
584 1
585 1
586 1
587 1
588 1
589 1
59 1
592 1
595 1
598 1
6 1
61 1
611 1
614 1
617 1
62 1
622 1
625 1
628 1
64 1
641 1
644 1
647 1
65 1
652 1
655 1
658 1
67 1
671 1
674 1
677 1
68 1
682 1
685 1
688 1
7 0
70 1
701 1
704 1
707 1
71 0
710 1
711 1
712 1
713 1
714 1
715 1
716 1
717 1
718 1
719 1
72 1
722 1
725 1
728 1
73 1
731 1
734 1
737 1
74 0
740 1
741 1
742 1
743 1
744 1
745 1
746 1
747 1
748 1
749 1
75 1
752 1
755 1
758 1
76 1
761 1
764 1
767 1
77 0
770 1
771 1
772 1
773 1
774 1
775 1
776 1
777 1
778 1
779 1
78 1
782 1
785 1
788 1
79 1
791 1
794 1
797 1
8 0
80 1
802 1
805 1
808 1
81 1
811 1
814 1
817 1
82 0
820 1
821 1
822 1
823 1
824 1
825 1
826 1
827 1
828 1
829 1
83 1
832 1
835 1
838 1
84 1
841 1
844 1
847 1
85 0
850 1
851 1
852 1
853 1
854 1
855 1
856 1
857 1
858 1
859 1
86 1
862 1
865 1
868 1
87 1
871 1
874 1
877 1
88 0
880 1
881 1
882 1
883 1
884 1
885 1
886 1
887 1
888 1
889 1
89 1
892 1
895 1
898 1
9 1
91 1
911 1
914 1
917 1
92 1
922 1
925 1
928 1
94 1
941 1
944 1
947 1
95 1
952 1
955 1
958 1
97 1
971 1
974 1
977 1
98 1
982 1
985 1
988 1