Python 归档 - SheepChef Blog https://shef.cc/category/it技术/python/ Rambling & Learning Mon, 29 Jul 2024 16:05:45 +0000 zh-Hans hourly 1 https://shef.cc/wp-content/uploads/cropped-SheepChef-Blog-Logo-2-32x32.png Python 归档 - SheepChef Blog https://shef.cc/category/it技术/python/ 32 32 用Python计算圆周率 π https://shef.cc/2024/07/29/calculate-pi/ https://shef.cc/2024/07/29/calculate-pi/#respond Sun, 28 Jul 2024 15:36:52 +0000 https://shef.cc/?p=2439 银河之角-发现知识的乐趣

使用Python精确计算任意位的圆周率。

用Python计算圆周率 π最先出现在SheepChef Blog

]]>
银河之角-发现知识的乐趣

各位读者想必对圆周率并不陌生——小学五年级,诸位就能接触到圆周率。

圆周率的简史

圆周率的几何定义十分简单,用圆的周长除以直径,就得到了圆周率。

但纯靠徒手测量,难免有些误差。古代的很多文明都有发现所谓“密率”,比如阿基米德率先提出 π 的大小应该在3.14到3.15之间,在算数并不发达的古希腊文明,将圆周率精确到两位小数已经是壮举。

汉代,中国人刘徽在《九章算术》中发明了“割圆法”,即对圆作外切和内接正N边形,不断逼近。他最终逼近到了正36边型,得到“徽率” π = 3.14,精确到两位小数。

祖冲之则继承了刘徽的算法,暴力计算到正24576边形,算出 π = 3.1415926,领先全世界几百年。

欧洲人在文艺复兴之后从中国人手中接走了红旗,达芬奇,欧拉,欧几里得等一众学者的出现让欧洲人发现了许多以更高效率计算 π 的方法,在电子计算机被发明之后,人们大可以想算几位就算几位。

计算 π 任意位数的精确值

公式

现在,我们通常用计算机循环迭代计算无穷级数,以此不断逼近 π 的值。为了提高效率,又要求这个无穷级数的收敛速度尽可能的快,这样我们就能以最少的计算量,算出最多的位数。一个常用的公式是马青公式,如下图。

马青公式由英国天文学教授约翰·马青于1706年发现。每计算一项就能将π的精确度提升1.4位小数。

现在公式摆在了面前,我们要设计一个Python脚本来实现它。

算法

在Python中,典型双精度浮点的精度上限不过几十位小数,如果我们要计算超过100位的圆周率,就不能简单地用变量和循环,这里需要引入 Decimal 库来实现十进制高精度计算。我们可以指定计算精度。我们还引入tqdm库,这样方便显示计算进度。

from decimal import *
from tqdm import tqdm

getcontext().prec = 100000 #十万位精度,需要9万余次迭代。

观察公式,不难发现公式大致分为两个部分,即那两个需要我们用循环迭代运算的无穷级数。这里把前面那项简称为前项,后面那项简称为后项,方便理解。

我们要先设定两项的初始值,分别是1/5和1/239。在式子中我们还能观察到式子中两项之间的符号在交替改变,所以设变量Flip来判断循环时该加上还是该减去。最后初始化Pi的变量,以及创建一个计次变量用于循环计次。

Pi = Decimal(0)
First = Decimal(1) / Decimal(5)
Last = Decimal(1) / Decimal(239)
Flip = False
Count = Decimal(1)

Acc = 95000 #迭代次数,每一次迭代可以推进1.4十进制位的精度。

接下来进入主要的循环运算部分

for i in tqdm(range(Acc),position=0,file=sys.stdout,desc="Progress"):
	if Count != Decimal(1):
		if not Flip:
			First = First - (Decimal(1) / ((Decimal(2)*Count - Decimal(1))*(Decimal(5)**(Decimal(2)*Count - Decimal(1)))))
			Last = Last - (Decimal(1) / ((Decimal(2)*Count - Decimal(1))*(Decimal(239)**(Decimal(2)*Count - Decimal(1)))))
			Flip = not Flip
		elif Flip:
			First = First + (Decimal(1) / ((Decimal(2)*Count - Decimal(1))*(Decimal(5)**(Decimal(2)*Count - Decimal(1)))))
			Last = Last + (Decimal(1) / ((Decimal(2)*Count - Decimal(1))*(Decimal(239)**(Decimal(2)*Count - Decimal(1)))))
			Flip = not Flip
		Pi = (Decimal(16) * First) - (Decimal(4) * Last)
	Count = Count + Decimal(1)
	if Count % 100 == 0 or Count == Acc - 1:
		#os.system('cls')  # 清空Windows控制台
		#tqdm.write(str(Pi))
		pass
Python

为了确保计算精度,所有的运算操作全部都要用Decimal对象进行,如果在此期间不进行任何控制台输出,将显著提高运行速度,尤其在精度特别高的时候。

最终的运算结果就是变量Pi的值,直接输出即可。

计算效率

Python是执行速度相对较慢的脚本编程语言,但Python代码相较于C++更易书写,高精度计算也更易在Python中实现。由于Python存在全局解释器锁,所以该脚本的计算速度很大程度上取决于CPU的单核性能,迭代的次数,以及要求的精确度。

对于现代消费级CPU(主频1.8Ghz)来说,使用该脚本计算十万位精确度的 π 值,大约需要2~3个小时。服务器专用的CPU则速度更快,因为其单核性能优于消费级的产品。

在库的选用方面,Decimal库的计算效率偏低,因为它的计算结果和过程依靠字符串来实现。

但Decimal可以精确计算数十万乃至数百万位的小数,且不会出现因二进制运算产生的循环小数误差,这一点是Numpy等一众基于C++编写的Python算术库所不具备的,在计算π的精确值这个问题上,我们并无其他更优的选择。

一万位以内的π值,脚本可以在3~5分钟之内完成计算,一千位则几秒便可完成计算。这是因为Python运行时对常用的数字进行了高速缓存,待高速缓存随着计算精度的升高而用尽,计算速度显著减慢。

完整代码

import math
from tqdm import tqdm
from decimal import *
import sys
import time
import os

Pi = Decimal(0)
Acc = int(input("How many times to calc:"))
getcontext().prec = round(1.4*Acc)
First = Decimal(1) / Decimal(5)
Last = Decimal(1) / Decimal(239)
Flip = False
Count = Decimal(1)


for i in tqdm(range(Acc),position=0,file=sys.stdout,desc="Progress"):
	if Count != Decimal(1):
		if not Flip:
			First = First - (Decimal(1) / ((Decimal(2)*Count - Decimal(1))*(Decimal(5)**(Decimal(2)*Count - Decimal(1)))))
			Last = Last - (Decimal(1) / ((Decimal(2)*Count - Decimal(1))*(Decimal(239)**(Decimal(2)*Count - Decimal(1)))))
			Flip = not Flip
		elif Flip:
			First = First + (Decimal(1) / ((Decimal(2)*Count - Decimal(1))*(Decimal(5)**(Decimal(2)*Count - Decimal(1)))))
			Last = Last + (Decimal(1) / ((Decimal(2)*Count - Decimal(1))*(Decimal(239)**(Decimal(2)*Count - Decimal(1)))))
			Flip = not Flip
		Pi = (Decimal(16) * First) - (Decimal(4) * Last)
	Count = Count + Decimal(1)
	if Count % 100 == 0 or Count == Acc - 1:
		#os.system('cls')  # 清空Windows控制台
		#tqdm.write(str(Pi))
		pass
print(str(Pi))
Python

写在最后

现在,用你自己的电脑计算圆周率并不是什么明智的选择。

因为早就有计算机科学家用超级计算机将圆周率计算到了几万亿位,你在网上也能轻松查询到一百万位圆周率的精确数值,所以大可不必自己用CPU计算。

那么问题来了,用自己的电脑计算 π 有什么意义?

我说,没准儿,它能检测一下你电脑CPU的单核性能如何。

用Python计算圆周率 π最先出现在SheepChef Blog

]]>
https://shef.cc/2024/07/29/calculate-pi/feed/ 0
【技术向】再也不怕收不到 Telegram 的短信验证 https://shef.cc/2023/01/16/%e3%80%90%e6%8a%80%e6%9c%af%e5%90%91%e3%80%91%e5%86%8d%e4%b9%9f%e4%b8%8d%e6%80%95%e6%94%b6%e4%b8%8d%e5%88%b0-telegram-%e7%9a%84%e7%9f%ad%e4%bf%a1%e9%aa%8c%e8%af%81/ https://shef.cc/2023/01/16/%e3%80%90%e6%8a%80%e6%9c%af%e5%90%91%e3%80%91%e5%86%8d%e4%b9%9f%e4%b8%8d%e6%80%95%e6%94%b6%e4%b8%8d%e5%88%b0-telegram-%e7%9a%84%e7%9f%ad%e4%bf%a1%e9%aa%8c%e8%af%81/#comments Mon, 16 Jan 2023 01:00:38 +0000 https://shef.cc/?p=1788 银河之角-发现知识的乐趣

中国运营商屏蔽了 Telegram 的短信验证码,我们需要找到一种真正的解决方案。

【技术向】再也不怕收不到 Telegram 的短信验证最先出现在SheepChef Blog

]]>
银河之角-发现知识的乐趣

warning 免责声明
《中国计算机信息网络国际联网管理规定》 计算机信息网络直接进行国际联网,必须使用邮电部国家公用电信网提供的国际出入口信道。任何单位和个人不得自行建立或者使用其他信道进行国际联网。如果您位于中国,那么请遵守以上规定。本站对您的行为不负任何责任。

如果你身处中国大陆,并且曾经设法注册了一个 Telegram 账号的话,你大概已经知道了一个遗憾的事实:中国运营商屏蔽了 Telegram 的短信验证码。这意味着,如果你仅有一台设备登录的话,一旦退出登录,那么将无法再次登录 Telegram ——直到你离开中国大陆的移动信号服务区。

要解决这个烦人的问题,我们先要搞清楚,运营商是怎么屏蔽短信的?在此之前,还需要搞清楚,一条国际短信是如何送到你的手机上的?

问题分析

现代移动通讯的技术基础是GSM(Global System for Mobile Communications),又称全球通讯系统,在中国俗称为2G网络。

2G网络可以为用户提供基础的打电话,发短信功能,而上网速度则非常缓慢,只有15-20K/s。通俗地说,假设一个国外的用户向国内的用户发送了一条短信,这条短信将会通过电缆或无线电基站等各种方式抵达国内的某处机房,在这里进行关键词检测,如果没问题,那么机房会通过基站把短信发给最终用户。

换SIM卡的方法是基本无效的,因为无论是国内的SIM卡还是国外的SIM卡,最终都得经过机房的检测,区别只是运营商不同而已。

我们需要找到一种真正的解决方案。

准备工作

在开始之前,你需要…..

  • 一个 「至少已经登陆在一台设备上」 的 Telegram 账号
  • Python运行环境,推荐3.10+
  • 学习一些基本的信息知识,例如Linux命令行,Python pip等等(本文非小白向)

Step 1. 申请一个 Telegram 开发者 API ID

前往 my.telegram.org ,在登陆框里输入你的手机号(即使收不到验证码),检查你的 Telegram 服务通知,复制验证码填到浏览器里并点击下一步。

登录后,你会看到两个功能,一个是销户,一个是申请API ID。

点击 “API delevopment tools”

选择“API development tools”,接着网页会让你填写一些基本信息,可以随便填。

一切结束后,你会看到API ID和API Hash

这是信息页面

注意,你的API Hash和API ID必须严格保密,否则别人可以冒用你的身份来写第三方 Telegram 客户端

Step 2. 配置Python环境

Python如何安装这种问题我就不赘述了,网上教程一大把

接下来的代码要用到telethon,安装telethon需要在命令行执行:

pip install telethon

Step 3. 获取一个 Telegram Session

Session 意为“会话”,你每一次登录 Telegram,都会创建一个新Session

我们的目的是在新设备上重新登陆一次 Telegram,拿到一个新的Session字符串。

你可以使用这个链接 (记得一开始选Telethon):Link

记得输入 t

获取Session相当于登录 Telegram,因此你需要输入自己账户的手机号,然后再次在 Telegram 服务通知里查阅验证码。

如果你开了二步验证,你还需要额外输入你的二步验证密码。

我不保证这个链接是安全的,但是我本人通过这个链接获取的Session,至今无事。如果你实在担心安全性,可以把脚本下载到本地运行。

请将你获取的Session字符串严格保密,任何人拿到你的Session都可以直接获取你 Telegram 账号的完整访问权限。

Step 4. 写代码

接下来,理论上你就要开始写Python脚本了,但是你不用写,这里已经帮你准备好了模板:

from telethon import TelegramClient, events
import logging
from telethon.sessions import StringSession
from telethon.tl.types import InputMediaPhoto,InputMediaPhotoExternal
logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s', level=logging.WARNING)
APP_ID = <你的APP ID>
API_HASH = <你的APP HASH>
SESSION = <你的SESSION>
client = TelegramClient(StringSession(SESSION), APP_ID, API_HASH)
#client = TelegramClient(StringSession(SESSION), APP_ID, API_HASH,proxy=("socks5", '127.0.0.1', 10808))
#如果你需要使用代理,那么请去掉上面那一行的注释,并注释掉上上行。代理配置请自行修改,本文不再赘述。
async def main():
    entity = await client.get_entity(777000)
    async for message in client.iter_messages(entity,1):
        print(message.raw_text)
with client:
    client.loop.run_until_complete(main())

将上述脚本的对应内容换成你的API ID, API HASH 和 SESSION,别忘了给后两个加上双引号。
下面是一个伪示例:

APP_ID = 12345678
API_HASH = "d84caca3caca4835abece79d4d16c57d"
SESSION = "XXXXXXXXXXXXXXXXX"

Step 5. 运行脚本

运行你的脚本,脚本应该会输出你 Telegram 服务通知的最后一条消息。

你可以对比一下输出的结果和 Telegram 服务消息,看看是否匹配。脚本的目的是通过一个额外的Session获取 Telegram 服务验证码,这样可以绕过SMS验证。

尾声: 拓展与提示

Session有有效期,最长是一年。

如果你想要保险一些的措施,可以租赁一台云服务器,然后利用定时任务来循环执行脚本。

每一次执行都会刷新这个Session的上线时间,这样你的Session只要不手动在 设置->隐私->设备 里注销,将会一直保持可用。

更高级的玩法是把脚本配合PHP和服务器使用,这样你就可以在没有任何其他设备(电脑)的情况下,通过浏览器快速地随时随地查阅验证码了。

下次如果你不小心手滑退出了 Telegram 账号,别再慌了!

【技术向】再也不怕收不到 Telegram 的短信验证最先出现在SheepChef Blog

]]>
https://shef.cc/2023/01/16/%e3%80%90%e6%8a%80%e6%9c%af%e5%90%91%e3%80%91%e5%86%8d%e4%b9%9f%e4%b8%8d%e6%80%95%e6%94%b6%e4%b8%8d%e5%88%b0-telegram-%e7%9a%84%e7%9f%ad%e4%bf%a1%e9%aa%8c%e8%af%81/feed/ 9