产生广义汉明数Python

时间:2018-08-11 07:17:01

标签: python number-theory

这是我的代码,用于在给定的限制下生成所有汉明数(也称为5平滑数)。 https://en.wikipedia.org/wiki/Smooth_number

  

在数论中,平滑(或易碎)数是一个整数,可以完全分解成较小的素数。例如,一个7平滑数字是一个素数最多为7的数字,因此49 = 7 ^ 2和15750 = 2×32×53×7都是7平滑的,而11和702 = 2×33 ×13不是

我知道生成数字的其他方法,但是我首先想到的功能对我来说很有意义,并且想知道如何将其扩展为7平滑,11平滑,...,n平滑数字。有没有更简单的方法来更改我的函数以在限制以下的素数之间循环而无需添加非常相似的代码行?

import math

def HammingFiveUnder(limit):
    hammings = []
    exp2 = int(math.log(limit, 2))
    exp3 = int(math.log(limit, 3))
    exp5 = int(math.log(limit, 5))
    for i in range(0, exp2+1):
        for j in range(0, exp3+1):
            for k in range(0, exp5+1):
                poss_ham = 2**i * 3**j * 5**k
                if poss_ham <= limit:
                    hammings.append(poss_ham)
    return sorted(hammings)

print(HammingFiveUnder(100))

3 个答案:

答案 0 :(得分:2)

使用笛卡尔积itertool.product函数的解决方案略有不同:

  

大致等同于生成器表达式中的嵌套for循环。例如,product(A,B)返回的结果与(A中x对应B中y对应(x,y)。)

n_primes是顺序需要的素数的数量。

from itertools import product as cartesianproduct # Cartesian product of input iterables.
from functools import reduce
import math

def prod(list_of_numbers):
    ''' Compute the product of the given numbers '''
    return reduce(lambda x,y: x*y, list_of_numbers)

def smoothnumbers(n_primes=3, limit=100):
    # List of the primes numbers:
    primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]

    # Compute the possible exponent ranges given the limit:
    max_exponents = [math.floor(math.log(limit, prime))
                     for prime in primes[:n_primes]]
    exponents_ranges = [range(max_exp+1) for max_exp in max_exponents]

    # loop
    smoothnumbers = []
    for exponents in cartesianproduct(*exponents_ranges):
        n = prod( factor**exp for factor, exp in zip(primes, exponents) )
        # print(exponents, n)
        if n <= limit:
            smoothnumbers.append(n)

    return sorted(smoothnumbers)

哪个给:

print( smoothnumbers(n_primes=2, limit=100) )
# [1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 27, 32, 36, 48, 54, 64, 72, 81, 96]

print( smoothnumbers(n_primes=3, limit=100) )
# [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36,
#  40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100]

print( smoothnumbers(n_primes=5, limit=100) )
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25,
#  27, 28, 30, 32, 33, 35, 36, 40, 42, 44, 45, 48, 49, 50, 54, 55, 56, 60, 63,
#  64, 66, 70, 72, 75, 77, 80, 81, 84, 88, 90, 96, 98, 99, 100]

答案 1 :(得分:1)

您可以保持相同的逻辑,只需要使用标准库中更合适的数据类型和itertools.product

itertools.product将为您提供列表项的所有组合,因此等效于嵌套循环。

import itertools

# returns (n,p) as n**p
def tuplePower(t):
  n, p = t
  return n**p

# returns the product of the list items
def multiplyIter(myIter):
  result = 1
  for i in myIter:
    result = result * i
  return result

def HammingFiveUnder(limit):
  hammings = []
  # iterable data structures
  multipliers = (2, 3, 5)
  exps = [int(math.log(limit, x)) for x in multipliers]
  # compose the list of ranges to replace nested for loops
  ranges_lists = [[i for i in range(0, n+1)] for n in exps]
  combo_list = list(itertools.product(*ranges_lists))
  # iterate through the list
  for combo_item in combo_list:
    poss_ham = multiplyIter(list(map(tuplePower, zip(multipliers, combo_item))))
    if poss_ham <= limit:
      hammings.append(poss_ham)
  return sorted(hammings)

print(HammingFiveUnder(100))

答案 2 :(得分:0)

一个可能的解决方案是列出所有可能的质数,然后使用itertools.combinations进行所有组合的计算,并将每个列表的元素相乘。我必须过滤掉所有的双重组合,因此仍有提速的潜力。

import numpy as np
import math
import itertools

def HammingFiveUnder(limit):
    hammings = []

    def prime_list():
        '''create a list with primes repeated as many times as they can maximally occur under the said limit in a prime factorisation'''
        list_with_repeated_primes = []   
        for prime in [2,3,5,7]: #change this for smooth number you want
            rep = int(math.log(limit, prime))
            for n in range(rep):
                list_with_repeated_primes.append(prime)
        return list_with_repeated_primes
    list_with_repeated_primes = prime_list()

#now make all possible combinations of primes and check against limit:
    comb = []
    for i in range(len(list_of_repeated_primes)):
        comb += itertools.combinations(list_of_repeated_primes,i+1)
    comb = np.unique(comb)
    for i in comb:
        poss_ham = np.prod(np.array(i))  
        if poss_ham <= limit:
            hammings.append(poss_ham)
    return sorted(hammings)

print(HammingFiveUnder(100))