查看: 210|回复: 3

用Python实现模n乘法逆元计算器:扩展欧几里得算法与Pygame GUI实践

[复制链接]
发表于 4 小时前 | 显示全部楼层 |阅读模式
在数论和密码学中,模运算下的乘法逆元是一个基础且重要的概念。给定正整数 n 和自然数 a,若存在整数 x 使得 ax ≡ 1 (mod n),则称 x 为 a 关于模 n 的乘法逆元。求解逆元常用扩展欧几里得算法,本文将结合 Python 实现该算法,并利用 Pygame 制作一个图形化的逆元计算器。

一、数学背景与判定条件

对自然数 a 和正整数 n,方程 ax ≡ 1 (mod n) 有解的充分必要条件是 gcd(a, n) = 1(即 a 与 n 互质)。这个结论可以通过扩展欧几里得算法证明:当 gcd(a, n) = 1 时,存在整数 x₀, y₀ 使得 ax₀ + ny₀ = 1,于是 ax₀ ≡ 1 (mod n),x₀ 模 n 即得一个逆元。当 gcd(a, n) ≠ 1 时,反证法可知方程无解。此外,在 0 ≤ x < n 范围内,逆元至多只有一个。

二、扩展欧几里得算法核心函数

Python 实现扩展欧几里得算法,返回 (x, y, g) 满足 ax + by = g = gcd(a, b)。在此基础上,只需判断 gcd 是否为 1 即可返回逆元(取模 n 的正数)。代码示例如下:
  1. def extended_euclidean(a, b):
  2.     if (a, b) == (0, 0):
  3.         raise ValueError("a and b cannot be both 0")
  4.     if b == 0:
  5.         return (1, 0, a)
  6.     x, y, g = extended_euclidean(b, a % b)
  7.     return (y, x - a // b * y, g)
  8. def calc_inverse_element(a, n):
  9.     x, _, gcd = extended_euclidean(a, n)
  10.     if gcd == 1:
  11.         return x % n
  12.     return None
复制代码

三、Pygame 图形界面完整实现

下面给出完整的逆元计算器程序,基于 Pygame 构建交互界面。用户输入 a 和 n,点击 Calculate 即可显示逆元 x 及验证等式。注意输入仅接受正整数。
  1. import pygame
  2. def extended_euclidean(a, b):
  3.     if (a, b) == (0, 0):
  4.         raise ValueError("a and b cannot be both 0")
  5.     if b == 0:
  6.         return (1, 0, a)
  7.     x, y, g = extended_euclidean(b, a % b)
  8.     return (y, x - a // b * y, g)
  9. def calc_inverse_element(a, n):
  10.     x, _, gcd = extended_euclidean(a, n)
  11.     if gcd == 1:
  12.         return x % n
  13.     return None
  14. # ===================== Pygame 初始化 =====================
  15. pygame.init()
  16. WIDTH, HEIGHT = 700, 480
  17. screen = pygame.display.set_mode((WIDTH, HEIGHT))
  18. pygame.display.set_caption("Inverse Element Calculator")
  19. WHITE = (255, 255, 255)
  20. BLACK = (0, 0, 0)
  21. GRAY = (220, 220, 220)
  22. BLUE = (50, 100, 200)
  23. RED = (200, 50, 50)
  24. GREEN = (50, 180, 50)
  25. font_input = pygame.font.SysFont("Arial", 36)
  26. font_text = pygame.font.SysFont("Arial", 32)
  27. font_result = pygame.font.SysFont("Arial", 38)
  28. font_equation = pygame.font.SysFont("Arial", 32)
  29. font_btn = pygame.font.SysFont("Arial", 34)
  30. INPUT_X = WIDTH // 2 - 110
  31. INPUT_WIDTH = 220
  32. INPUT_HEIGHT = 50
  33. input_a_rect = pygame.Rect(INPUT_X, 110, INPUT_WIDTH, INPUT_HEIGHT)
  34. input_a_text = ""
  35. a_active = False
  36. input_n_rect = pygame.Rect(INPUT_X, 180, INPUT_WIDTH, INPUT_HEIGHT)
  37. input_n_text = ""
  38. n_active = False
  39. btn_rect = pygame.Rect(WIDTH // 2 - 150, 260, 300, 60)
  40. btn_text = "Calculate"
  41. result_text = ""
  42. equation_text = ""
  43. result_color = BLACK
  44. running = True
  45. while running:
  46.     screen.fill(WHITE)
  47.     label_a = font_text.render("Input a:", True, BLACK)
  48.     screen.blit(label_a, (INPUT_X - 120, 118))
  49.     label_n = font_text.render("Input n:", True, BLACK)
  50.     screen.blit(label_n, (INPUT_X - 120, 188))
  51.     pygame.draw.rect(screen, BLUE if a_active else GRAY, input_a_rect, 2)
  52.     screen.blit(font_input.render(input_a_text, True, BLACK), (input_a_rect.x+10, input_a_rect.y+5))
  53.     pygame.draw.rect(screen, BLUE if n_active else GRAY, input_n_rect, 2)
  54.     screen.blit(font_input.render(input_n_text, True, BLACK), (input_n_rect.x+10, input_n_rect.y+5))
  55.     pygame.draw.rect(screen, BLUE, btn_rect, border_radius=8)
  56.     btn_surface = font_btn.render(btn_text, True, WHITE)
  57.     screen.blit(btn_surface, (btn_rect.centerx - btn_surface.get_width()//2, btn_rect.centery - btn_surface.get_height()//2))
  58.     result_surface = font_result.render(result_text, True, result_color)
  59.     screen.blit(result_surface, (WIDTH // 2 - result_surface.get_width()//2, 350))
  60.     formula = font_equation.render(equation_text, True, BLACK)
  61.     screen.blit(formula, (WIDTH // 2 - formula.get_width()//2, 420))
  62.     for event in pygame.event.get():
  63.         if event.type == pygame.QUIT:
  64.             running = False
  65.         if event.type == pygame.MOUSEBUTTONDOWN:
  66.             if input_a_rect.collidepoint(event.pos):
  67.                 a_active = True
  68.                 n_active = False
  69.             elif input_n_rect.collidepoint(event.pos):
  70.                 n_active = True
  71.                 a_active = False
  72.             elif btn_rect.collidepoint(event.pos):
  73.                 result_text = ""
  74.                 try:
  75.                     a = int(input_a_text)
  76.                     n = int(input_n_text)
  77.                     if a <= 0 or n <= 0:
  78.                         result_text = "ERROR: Please input positive integers!"
  79.                         result_color = RED
  80.                     else:
  81.                         inv = calc_inverse_element(a, n)
  82.                         if inv is not None:
  83.                             result_text = f"x: {inv}"
  84.                             result_color = GREEN
  85.                             equation_text = f"{a} * {inv} ≡ 1 (mod {n})"
  86.                         else:
  87.                             result_text = f"ERROR: {a} and {n} are not relatively prime, no inverse exists!"
  88.                             result_color = RED
  89.                 except ValueError:
  90.                     result_text = "ERROR: Please input valid integers!"
  91.                     result_color = RED
  92.             else:
  93.                 a_active = False
  94.                 n_active = False
  95.         if event.type == pygame.KEYDOWN:
  96.             if a_active:
  97.                 if event.key == pygame.K_BACKSPACE:
  98.                     input_a_text = input_a_text[:-1]
  99.                 elif event.unicode.isdigit():
  100.                     input_a_text += event.unicode
  101.             if n_active:
  102.                 if event.key == pygame.K_BACKSPACE:
  103.                     input_n_text = input_n_text[:-1]
  104.                 elif event.unicode.isdigit():
  105.                     input_n_text += event.unicode
  106.     pygame.display.flip()
  107. pygame.quit()
复制代码

四、运行与使用

将上述代码保存为 inverse_element_calculator.py,在终端执行
  1. python3 inverse_element_calculator.py
复制代码
即可启动窗口。输入正整数 a 和 n,点击 Calculate 按钮,程序会计算并显示逆元 x 及其模等式验证。若 a 与 n 不互质,则提示错误。由于扩展欧几里得算法效率极高,即使 a 和 n 达到千万级别(如 a=63245986, n=102334155),也能瞬间返回结果。

五、技术要点总结

* 核心算法:递归实现扩展欧几里得,时间复杂度 O(log min(a,n))。
* 逆元判定:仅当 gcd=1 时存在,否则返回 None。
* 界面交互:Pygame 处理鼠标点击与键盘输入,限制输入为数字字符。
* 适用场景:密码学 RSA 密钥生成、数论计算、竞赛编程等需要模逆元的场景。

本文通过数学原理讲解与完整代码实现,展示了如何利用 Python 与 Pygame 构建一个实用的模 n 乘法逆元计算器,读者可直接复制代码运行或修改扩展。
回复

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: 用Python实现模n乘法逆元计算器:扩展欧几里得算法与Pygame GUI实践

这个实现挺清晰的,把数学原理和图形界面结合起来,很适合用来教学或者快速验证逆元。扩展欧几里得算法的递归写法也很简洁,不过递归深度在n很大时可能会受限,可以考虑迭代版本试试。 接口上,输入只接受正整数,但如果用户误输入字母或小数,会直接报错退出吧?加个输入校验或者异常处理会更友好。另外计算结果只显示逆元和等式,如果能展示一下扩展欧几里得算出的中间系数x和y,或者展示gcd的步骤,会更便于理解算法过程。 Pygame界面部分,最后一段代码好像被截断了(screen.blit之后少了循环结束和事件处理的部分),是不是粘贴时漏了?期待看到完整的效果图或者演示视频。整体来说很实用的工具,感谢分享!
回复 支持 反对

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: 用Python实现模n乘法逆元计算器:扩展欧几里得算法与Pygame GUI实践

楼主这个帖子写得真好,把数学原理、算法推导和GUI实现都讲得很清楚。对于刚学数论或密码学的同学来说,能直接跑一个可视化工具验证逆元,理解起来会直观很多。 我特别喜欢你给出的 `extended_euclidean` 递归实现,简洁又优雅。判断 `gcd(a, n) == 1` 后返回 `x % n` 的做法也很规范,保证了结果在 `[0, n-1]` 范围内。 Pygame 部分界面布局简单明了,输入框、按钮、结果显示都安排得很合理。有一点小建议:如果用户输入了非数字字符,程序可能会直接崩溃,可以考虑捕获 `ValueError` 或者加一些输入过滤(比如只允许数字和退格)。另外,当 `a` 和 `n` 不互质时,显示提示“无解”或者“逆元不存在”会更友好,现在 `calc_inverse_element` 返回 `None`,界面上好像没有处理这个情况,可能会显示空白或者报错。 总体来说是很好的实践分享,既巩固了算法知识,又锻炼了GUI编程。感谢楼主的干货!
回复 支持 反对

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: 用Python实现模n乘法逆元计算器:扩展欧几里得算法与Pygame GUI实践

楼主分享得很详细,代码结构和数学原理都讲得很清楚,Pygame 界面也设计得简洁实用,非常适合初学者理解模逆元的概念和算法实现。一个小建议:可以考虑在输入框中加入字符过滤,防止非数字输入导致程序崩溃;另外如果能加上“清除”按钮或者显示运算耗时,交互体验会更完善。整体来说非常棒,收藏学习!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-29 14:01 , Processed in 0.048636 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部