Python程序笔记20230305

n 以内能被 m 整除的数的和、积

最初版本

计算指定数字内所有偶数的和

n = int(input("请输入指定的n:"))  
i = 0  
mysum = 0  
  
while i <= n:  
	if i % 2 == 0:  
		mysum = mysum + i  
i = i + 1  
  
print(f"{n}以内的所有偶数的和是{mysum}")  
print("{0}以内的所有偶数的和是{1}".format(n, mysum))

对于两行输出代码:
第一行代码使用了 f-string,语法形式为在字符串前加上字母 f,然后使用花括号 {} 括起来的变量名或表达式,就可以在字符串中插入变量的值。在这个例子中,f-string 会将变量 n 和 mysum 的值插入到字符串中。
第二行代码使用了字符串的 format() 方法,它可以用来替换字符串中的占位符。在这个例子中,字符串中的占位符是 {0} 和 {1},分别对应 format() 方法的第一个参数和第二个参数。在 format() 方法中,可以按照顺序传递参数值,或者使用关键字参数来指定参数的位置。输出结果与 f-string 相同

优化方法

使用 for 循环

n = int(input("请输入指定的n"))
mysum = 0

for i in range(0, n+1, 2):
    mysum += i

print(f"{n}以内的所有偶数的和是{mysum}")

使用列表推导式

n = int(input("请输入指定的n:"))
mysum = sum([i for i in range(n+1) if i % 2 == 0])
print(f"{n}以内的所有偶数的和是{mysum}")

使用内置 math 模块

import math
n = int(input("请输入指定的n:"))
mysum = math.ceil(n/2) * (n//2 + 1)
print(f"{n}以内的所有偶数的和是{mysum}")

使用 math.ceil() 函数来将 n 除以 2 并向上取整。这里使用向上取整的原因是为了确保当 n 为奇数时,也能够正确计算偶数和。例如,当 n 为 5 时,5//2 = 22*3 = 6,这样就能正确计算 5 以内的偶数和了。
使用整除运算符 // 和取模运算符 % 来计算 n 的一半和 n 的下取整值,然后将它们相乘得到所有偶数的和。这个计算公式的思路是:偶数和 = 2 + 4 + 6 + ... + n(n 为偶数)= 2 * (1 + 2 + 3 + ... + n/2) = 2 * [n/2 * (n/2 + 1)/2] = n/2 * (n/2 + 1),其中 [ ] 表示向下取整。注意,当 n 为奇数时,n//2 会向下取整,因此会忽略掉最后一个奇数,但这并不影响结果,因为最后一个奇数一定不是偶数。

使用 peephole 优化技术

n = int(input("请输入指定的n:"))
i = 0
mysum = 0

while i <= n:
    if not i & 1: # 使用位运算代替求余运算
        mysum += i # 使用增量赋值代替普通赋值
    i += 1

print(f"{n}以内的所有偶数的和是{mysum}")

在 Python 中,位运算比求余运算更快,因此可以提高代码的执行效率。在这个例子中,使用了位运算 & 来判断 i 是否为偶数。由于偶数的二进制表示的最后一位为 0,因此 i & 1 的结果为 0 就意味着 i 是偶数。这样就避免了使用 % 操作符来求余数,提高了代码的性能。
使用了增量赋值 += 代替普通赋值。增量赋值可以将两个操作合并成一个,从而提高代码的执行效率。
这些优化方法可能对于小规模的数据集并没有太大的作用,但是在处理大规模数据集时,它们能够提高代码的执行效率,从而减少程序的运行时间和资源消耗。

关于位运算

当我们将一个二进制数和 1 进行按位与(&)操作时,只有最后一位是 1 的二进制数和 1 进行按位与操作的结果是 1,其余情况下结果都是 0。
如果一个数是偶数,它的二进制表示的最后一位是 0,那么它和 1 进行按位与操作的结果也是 0;
如果一个数是奇数,它的二进制表示的最后一位是 1,那么它和 1 进行按位与操作的结果就是 1。
需要注意的是,在进行位运算时,应该使用位运算符 &|^~,而不是逻辑运算符 andornot。因为位运算符是针对二进制数的,它们操作的是二进制数的每一位,而逻辑运算符是针对布尔值的,它们操作的是 True 和 False。

进阶版本 1

n = int(input("请输入指定的n:"))
m = int(input("请输入指定的m:"))

sum_divisible_by_m = sum([i for i in range(m, n+1) if i % m == 0])
product_divisible_by_m = 1
for i in range(m, n+1):
    if i % m == 0:
        product_divisible_by_m *= i

print(f"{n}以内能被{m}整除的数的和是{sum_divisible_by_m}")
print(f"{n}以内能被{m}整除的数的积是{product_divisible_by_m}")

这段代码首先通过 input() 函数获取用户输入的 n 和 m,然后分别使用 sum() 函数和 for 循环来计算小于等于 n 且能被 m 整除的数的和和积。
需要注意的是,第 4 行代码中的列表推导式中的 range() 函数使用了起始值 m,这是为了确保生成的列表中的第一个元素是能被 m 整除的数。同时,第 5 行代码中的 for 循环也从 m 开始遍历,这是为了避免重复计算 m。如果不从 m 开始遍历,那么 m 就会被计算两次,一次在列表推导式中,一次在 for 循环中。
在 Python 中没有内置的连乘函数,但可以通过使用内置函数 reduce() 或者 NumPy 库中的 prod() 函数来实现连乘。

reduce() 函数

reduce() 函数位于 functools 模块中,它可以对一个序列中的元素进行累积计算。

from functools import reduce

product = reduce(lambda x, y: x * y, [1, 2, 3, 4, 5])
print(product)  # 输出 120

使用 reduce() 函数将列表 [1, 2, 3, 4, 5] 中的所有元素累乘起来。reduce() 函数接受两个参数:一个函数和一个序列。函数用于对序列中的元素进行累积计算,序列是要计算的元素。在这个例子中,我们使用 lambda 表达式定义了一个匿名函数来计算累乘结果,然后将这个函数和列表 [1, 2, 3, 4, 5] 传递给 reduce() 函数。

prod() 函数

如果需要对 NumPy 数组进行连乘计算,可以使用 NumPy 库中的 prod() 函数。

import numpy as np

product = np.prod([1, 2, 3, 4, 5])
print(product)  # 输出 120

修改后的结果

from functools import reduce

n = int(input("请输入指定的n:"))
m = int(input("请输入指定的m:"))

sum_divisible_by_m = sum([i for i in range(m, n+1, m)])
product_divisible_by_m = reduce(lambda x, y: x * y, range(m, n+1, m), 1)

print(f"{n}以内能被{m}整除的数的和是{sum_divisible_by_m}")
print(f"{n}以内能被{m}整除的数的积是{product_divisible_by_m}")

  • lambda是一种创建匿名函数的方式,它可以让你在一行代码中定义一个简单的函数,而不需要使用def关键字。lambda函数的语法是lambda 参数: 表达式,它表示一个接受参数并返回表达式计算结果的函数。例如,lambda x, y: x * y就是一个接受两个参数x和y,并返回它们相乘结果的函数。
  • reduce是一个内置函数,它可以对一个可迭代对象(如列表)中的元素进行累积操作,从而得到一个单一的值。reduce函数的语法是reduce(函数, 可迭代对象, 初始值),它表示从左到右依次将可迭代对象中的元素和初始值作为参数传递给函数,并将函数的返回值作为下一次调用的初始值,直到可迭代对象中的元素遍历完毕。例如,reduce(lambda x, y: x + y, [1, 2, 3, 4], 0)就是对列表[1, 2, 3, 4]中的元素进行求和操作,并以0作为初始值,最终得到10。

代码reduce(lambda x, y: x * y, range(m, n + 1, m), 1)是什么意思呢?

  • range(m, n + 1, m)是一个生成器,它可以产生从m到n(包含n)之间以m为步长的整数序列。
  • lambda x, y: x * y是一个接受两个参数x和y,并返回它们相乘结果的函数。
  • reduce(lambda x, y: x * y, range(m, n + 1, m), 1)就是对range(m, n + 1, m)中的元素进行累乘操作,并以1作为初始值。例如,如果m=2,n=10,那么这个表达式就相当于计算(1 * 2 * 4 * 6 * 8 * 10),最终得到3840。

需要注意的是,代码中的 range() 函数使用了步长 m,这是为了确保生成的序列中的所有元素都能被 m 整除。同时,第 5 行代码中的列表推导式中的 range() 函数也使用了步长 m,这是为了避免重复计算。如果不使用步长 m,那么就会生成一个包含所有小于等于 n 的数的列表,然后再筛选出能被 m 整除的数,这样就会浪费一些时间和空间。

进阶版本 2

import numpy as np
from functools import reduce

# 输入检查:确保 n 和 m 都是正整数
while True:
    try:
        n = int(input("请输入指定的 n:"))
        m = int(input("请输入指定的 m:"))
        if n > 0 and m > 0:
            break
        else:
            print("n 和 m 必须是正整数,请重新输入")
    except ValueError:
        print("n 和 m 必须是正整数,请重新输入")

# 如果 n 太大,就使用 1000000 代替
if n > 1000000:
    n = 1000000
    print("n 太大,已经自动调整为 1000000")

# 计算能被 m 整除的数的和和积
sum_divisible_by_m = sum([i for i in range(m, n+1, m)])
product_divisible_by_m = reduce(lambda x, y: x * y, range(m, n+1, m), 1)
product_divisible_by_m1 = np.prod(range(m, n+1, m))

# 输出结果
print(f"{n} 以内能被 {m} 整除的数的和是 {sum_divisible_by_m}")
print(f"{n} 以内能被 {m} 整除的数的积是 {product_divisible_by_m}")
print(f"{n} 以内能被 {m} 整除的数的积是 {product_divisible_by_m1}")

热门相关:斗神战帝   豪门闪婚:帝少的神秘冷妻   豪门闪婚:帝少的神秘冷妻   仗剑高歌   豪门闪婚:帝少的神秘冷妻