Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import math
- import sys
- from tabulate import tabulate
- # This terrible python code is provided by Kaelygon
- #
- # Find divisibility rule by prime P: P * N = a * 10^b + c
- # such that an integer can be split in two parts A and B
- # and reduced to a smaller number by simulating 10^b division and modulus
- # using string manipulation and addition: B*a-A*c
- # Matt Parker explanation https://youtu.be/6pLz8wEQYkA
- #Find divisibility rules P * N = a * 10^b + c
- def findDivRules(P, aRange, cRange, bRange):
- rules = []
- bMin=int(math.log10(abs(P))+1)
- for b in range(bMin, bRange):
- bPowTen=10**b # 10^b
- for a in range(1, aRange):
- ab = a*bPowTen # a*b^10
- if ab<P: continue
- for c in range(-cRange, cRange):
- PN = ab + c # P * N = a * 10^b + c
- if PN<=P or PN%P!=0 or c==0: continue # skip trivial solutions
- N = PN//P
- rules.append((P, N, a, b, c))
- # Sort by smallest b and c
- rules.sort(key=lambda x: (x[3], abs(x[4])))
- return rules
- #Output formatting
- def printRuleTables(rules):
- headers = ["P", "N", "a", "b", "c", "P*N"]
- table = [[P, N, a, b, c, P * N] for P, N, a, b, c in rules]
- print(tabulate(table, headers=headers, tablefmt="plain")) # Use "plain", "grid", or others
- def printDivIters(iterTable):
- headers = ["A.B", "B*a-A*c", "Intermed"]
- table = [[f"{A}.{B}", f"{B}*{a}-{A}*{c}", iterNum] for A, B, iterNum, a, c in iterTable]
- print(tabulate(table, headers=headers, tablefmt="plain"))
- # Test function that reduces a number by using the given rules
- def divByRule(rules,num):
- P,N,a,b,c=rules
- print(f"Using rules P={P} a={a} b={b} c={c}")
- print(f"Testing {num} divisibility by {P}\n")
- iterNum=num
- iterHistory=[num]
- iterTable=[]
- maxIters=100
- iterCount=0
- iterSmallest=num
- while(iterCount<maxIters): #Iterate till 10s table has been reached
- iterCount+=1
- if iterNum<iterSmallest: iterSmallest=iterNum
- powTen=10**b
- A=iterNum//powTen
- B=iterNum%powTen
- if A==0 or B==0: break #Break if invalid A or B
- iterNum=B*a-A*c
- #print(f"{A}.{B} \t= {B}*{a}-{A}*{c} = {iterNum}")
- iterTable.append([A,B,iterNum,a,c])
- #Keep history to check whether the iteration is in a loop
- if iterNum in iterHistory: break
- iterHistory.append(iterNum)
- printDivIters(iterTable)
- print("\n")
- factor=iterSmallest/P
- print(f"Smallest iteration {iterSmallest} = {P}*{factor:g}")
- wholeNum=math.floor(factor)
- if factor != wholeNum:
- print(f"Not divisible by {P}")
- print(f"Remainder of {num}/{P} is {num%P}")
- else:
- print(f"{num} is divisible by {P}")
- return iterNum
- #Simple rotate right LCG for deterministic results
- def rorLCG(seed):
- modulus=0xFFFFFFFFFFFFFFFF #2^64-1
- bits=modulus.bit_length()
- shift=int((bits+1)/3)
- randNum=(seed>>shift)|((seed<<(bits-shift))&modulus) #RORR
- randNum=randNum*3343+11770513 #LCG
- randNum&=modulus
- return randNum
- def randDivRuleTest(rules,testProductsP):
- print("\nExample:")
- P=rules[0]
- randNum=rorLCG(P) #use the prime as seed
- minSize=P+17
- maxSize=P+P//2+minSize
- randPN=1
- if testProductsP:
- mult=randNum%maxSize+minSize
- randPN=P*mult # random product of P
- else:
- randPN=randNum%(maxSize**2)+minSize**2
- if randPN%P==0: randPN+=1 # ensure the test number is not product of P
- num=divByRule(rules,randPN)
- def main():
- defaultP = 313
- P = int(sys.argv[1]) if len(sys.argv) > 1 else defaultP
- if P==0: P=defaultP
- digitCount=int(math.log10(abs(P))+1)
- aRange = 10 # Second split 'B' multiplier
- bRange = digitCount*2+1 # 'b' sets the tested number split right to left
- cRange = abs(P//20) # First split 'A' multiplier
- #minimums
- if bRange<5 : bRange=5
- if cRange<16 : cRange=16
- maxDisplay=10
- testProductsP = True # Whether we should test divisibility rules with known products of P
- #Computation starts
- rules = findDivRules(P, aRange, cRange, bRange)
- if rules:
- print(f"Found {len(rules)} rules for {P}, showing first {maxDisplay}:\n")
- printRuleTables(rules[:maxDisplay]) # Display first 10 rules
- else:
- print(f"No rules found for {P}")
- return 0
- randDivRuleTest(rules[0],testProductsP)
- if __name__=="__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement