news 2026/6/23 19:34:11

用SymPy自动计算抛物线求根、判别式与顶点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用SymPy自动计算抛物线求根、判别式与顶点

痛点场景还原

假设我要做一个演示:固定a=1, c=2,让b从 -3 滑到 3,观察抛物线与 x 轴交点个数的变化。
如果纯手算,我可能会这样写Manim代码:

from manim import * import math class PainfulDemo(Scene): def construct(self): a, c = 1, 2 b_tracker = ValueTracker(-3) axes = Axes(x_range=[-5,5], y_range=[-1,6]) # 抛物线 graph = always_redraw(lambda: axes.plot( lambda x: a*x**2 + b_tracker.get_value()*x + c )) # 计算交点 —— 这里就是噩梦开始的地方 def get_roots(): b = b_tracker.get_value() disc = b**2 - 4*a*c if disc >= 0: root1 = (-b + math.sqrt(disc)) / (2*a) # 负数平方根直接报错 root2 = (-b - math.sqrt(disc)) / (2*a) return [root1, root2] else: return [] # 如果忘了判断,上面一行就炸了 dots = always_redraw(lambda: VGroup(*[ Dot(axes.coords_to_point(r, 0)) for r in get_roots() ])) self.add(axes, graph, dots) self.play(b_tracker.animate.set_value(3), run_time=5) self.wait(1)

  • 我必须手动写出求根公式,反复检查符号。
  • 判别式<0时要手动跳过,否则math.sqrt抛异常,动画中断。
  • 得到的只是浮点近似值,不能显示精确的根式表达(如 √22)。
  • 如果再加「自动标注顶点」,还得再手算一次导数或配方法。

这些体力活完全可以交给符号计算库SymPy,让动画代码只关心“展示什么”,而不是“怎么算”。

2. SymPy 解决方案介绍

SymPy 可以帮我们把求根、判别式计算、顶点坐标求解全部自动化,而且返回精确的符号表达式。

import sympy as sp x = sp.Symbol('x', real=True) a_val, c_val = 1, 2 b_sym = sp.Symbol('b') # 定义二次函数 expr = a_val * x**2 + b_sym * x + c_val # 1. 判别式 delta = b_sym**2 - 4 * a_val * c_val # b² - 8 # 2. 求根 —— 一行搞定,自动给出含根号的精确解 roots = sp.solve(expr, x) # 输出:[-b/2 - sqrt(b**2 - 8)/2, -b/2 + sqrt(b**2 - 8)/2] # 3. 求顶点(导数求极值) vertex_x = sp.solve(sp.diff(expr, x), x)[0] # -b/2 vertex_y = expr.subs(x, vertex_x) # 代入得到顶点纵坐标
  • solve返回的根自带根号,当判别式<0时,它会变成复数形式(如-b/2 - I*sqrt(8 - b**2)/2),我们只需判断虚部是否为 0 就能筛出实根。
  • 顶点坐标也不用背公式,diff求导 +solve一步到位。

Manim中,我们只需要把数值b传入SymPy表达式,调用evalf()就可以快速得到高精度结果,彻底告别手写公式。

3. Manim 联动实战

下面是一个完整的动画场景:b变化时,抛物线、交点、顶点、判别式与交点个数文本全部自动更新。

from manim import * import sympy as sp class QuadraticRootDance(Scene): def construct(self): # ========== SymPy 符号准备 ========== x_sym = sp.Symbol("x", real=True) a_val, c_val = 1, 2 # 固定 a, c,只让 b 变化 b_sym = sp.Symbol("b") expr = a_val * x_sym**2 + b_sym * x_sym + c_val # 判别式表达式 delta_expr = b_sym**2 - 4 * a_val * c_val # b² - 8 # 顶点 x 坐标(求导) vertex_x_expr = sp.solve(sp.diff(expr, x_sym), x_sym)[0] # -b/2 # 顶点 y 坐标 vertex_y_expr = expr.subs(x_sym, vertex_x_expr) # ========== Manim 场景搭建 ========== axes = Axes( x_range=[-5, 5, 1], y_range=[-1, 7, 1], axis_config={"include_numbers": True, "font_size": 18}, tips=False, ).add_coordinates() self.play(Create(axes)) b_tracker = ValueTracker(-3) # b 初始值 -3 # 抛物线:always_redraw 保证系数一更新图像就重绘 graph = always_redraw( lambda: axes.plot( lambda x: a_val * x**2 + b_tracker.get_value() * x + c_val, color=BLUE ) ) self.add(graph) # 交点集合(实心圆点) roots_dots = always_redraw( lambda: self.get_roots_dots(axes, b_tracker, x_sym, expr) ) self.add(roots_dots) # 顶点标记 vertex_dot = always_redraw( lambda: self.get_vertex_dot(axes, b_tracker, vertex_x_expr, vertex_y_expr) ) self.add(vertex_dot) # 动态文本:判别式 & 交点个数 info_text = always_redraw( lambda: self.get_info_text(b_tracker, delta_expr, x_sym, expr) ) info_text.to_corner(UR) self.add(info_text) # 动画:b 从 -3 滑到 3 self.play(b_tracker.animate.set_value(3), run_time=5, rate_func=linear) self.wait() # ---------- 辅助方法(内部封装 SymPy 计算)---------- def get_roots_dots(self, axes, tracker, x_sym, expr): """返回当前参数下所有实根对应的 Dot""" b_val = tracker.get_value() # 用 SymPy 解方程,并数值化 roots = sp.solve(expr.subs("b", b_val), x_sym) real_roots = [] for r in roots: r_num = complex(r.evalf()) # 转为 Python 复数判断虚实 if abs(r_num.imag) < 1e-8: # 虚部为 0 -> 实根 real_roots.append(r_num.real) # 为每个实根创建红点 dot_group = VGroup() for rx in real_roots: dot_group.add(Dot(axes.coords_to_point(rx, 0), color=RED)) return dot_group def get_vertex_dot(self, axes, tracker, vx_expr, vy_expr): """返回顶点位置的 Dot""" b_val = tracker.get_value() vx = float(vx_expr.subs("b", b_val).evalf()) vy = float(vy_expr.subs("b", b_val).evalf()) return Dot(axes.coords_to_point(vx, vy), color=YELLOW) def get_info_text(self, tracker, delta_expr, x_sym, expr): """生成判别式与交点个数的信息文本""" b_val = tracker.get_value() delta_val = float(delta_expr.subs("b", b_val).evalf()) # 判断实根个数(用 solve 求全部根,再筛实根) roots = sp.solve(expr.subs("b", b_val), x_sym) real_count = sum(1 for r in roots if abs(complex(r.evalf()).imag) < 1e-8) text1 = MathTex( f"\\Delta = {delta_val:.2f}", tex_to_color_map={f"\\Delta = {delta_val:.2f}": GREEN}, font_size=24, ) text2 = MathTex( f"\\text{{交点个数:}}{real_count}", tex_template=TexTemplateLibrary.ctex, font_size=24, ) text = VGroup(text1, text2).arrange(RIGHT, buff=1).shift(UP) return text

关键点解释:

  • SymPy提前准备好符号表达式,always_redraw里只做数值代入 + 求值,保证运行流畅。
  • complex(r.evalf()).imag判断虚部是否为 0,优雅地区分实根与复根,完全不用手动写条件分支。
  • 顶点坐标直接由diff推导,动画中总有一个黄色圆点稳稳跟随抛物线顶点。
  • 左上角文本实时显示判别式的值和交点个数,看一眼就能对应上「$ \Delta >0 两个交点,两个交点, \Delta=0 一个交点,一个交点, \Delta<0 $无交点」。

4. 效果展示说明

运行这个场景,你会看到:

  • 一根蓝色抛物线,开口向上(a=1),与 y 轴交于 2。
  • 随着b-3匀速滑到3
    • 开始b=-3时,判别式 Δ=1>0Δ=1>0,抛物线与 x 轴有两个红色交点。
    • 当 b 经过 $ -\sqrt{8} \approx -2.828 时,两交点靠拢,∗∗重合为一个点∗∗(时,两交点靠拢,∗∗重合为一个点∗∗( \Delta=0 $),此时左上角显示「交点个数:1」。
    • 紧接着 ΔΔ变成负数,所有红点消失,抛物线悬浮在x轴上方,与x轴无交点。
    • 当 b 跨越 √88时,两点再次出现并逐渐远离。
  • 整个过程,黄色顶点一直精准地落在抛物线最低点,随b移动而滑动。
  • 左上角的 ΔΔ 数值和交点个数同步刷新,完全不需要手动干预。

5. 小结

SymPyManim动画里的角色很纯粹:把数学计算还给计算机,把视觉表达留给你。
手算求根公式、判断判别式、求导数零点……这些重复且易错的体力活,SymPy一句solve、一句diff就能完美代劳。

动画代码的逻辑因此变得清晰——你只负责告诉Manim“什么东西应该画在什么位置”,而“位置怎么算”就让SymPy这个符号大脑去完成。

合集: manim动画

分类: databook

标签: databook, manim

免责声明:本内容来自平台创作者,博客园系信息发布平台,仅提供信息存储空间服务。

好文要顶 关注我 收藏该文 微信分享

wang_yb
粉丝 - 717 关注 - 6

+加关注

0

0

升级成为会员

« 上一篇: 一次函数图像工厂:用 SymPy 自动生成 y=kx+b 对比动画
» 下一篇: 用SymPy自动求解三角形构造与全等条件验证

posted @ 2026-06-05 16:31 wang_yb 阅读(113) 评论(0) 收藏 举报

刷新页面返回顶部

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/23 19:27:50

2026年腾讯地图LBS:社交地产出行AR三维地图技术方案

2026年腾讯地图LBS&#xff1a;社交地产出行AR三维地图技术方案 随着数字化进程的加速推进&#xff0c;位置服务&#xff08;LBS&#xff09;已成为连接物理世界与数字世界的核心纽带&#xff0c;企业对高精度、全场景、智能化地图服务的需求正经历深刻变革。作为腾讯产业互联网…

作者头像 李华
网站建设 2026/6/23 19:24:20

2026 最便宜 GPT5.5 API 密钥代购

2026 最便宜 GPT5.5 API 密钥代购&#xff1a;别只看单价&#xff0c;先把账算清楚很多个人开发者和小团队找 GPT5.5 API 密钥&#xff0c;第一反应是搜“便宜”“代购”“低价套餐”。实际接入后才发现&#xff0c;真正影响成本的不只是每百万 token 单价&#xff0c;还有并发…

作者头像 李华
网站建设 2026/6/23 19:16:52

软文发稿平台怎么选?从资源、优化、售后看懂平台差距

当下软文营销早已脱离单纯“发稿曝光”的初级阶段。随着智能信息检索技术迭代&#xff0c;用户获取资讯的场景持续升级&#xff0c;稿件是否具备优质内容结构、权威媒体背书、规范语义逻辑&#xff0c;直接决定了传播覆盖面与长效曝光效果。原本只追求发布数量、低价铺量的营销…

作者头像 李华
网站建设 2026/6/23 19:09:09

蛋仔网:CSDN技术文章怎么写,讲清低负载看板和安全记录

CSDN更适合写技术可信度内容。 蛋仔网相关技术文可以讲低负载看板、缓存快照、日志边界和账号安全记录&#xff0c;重点解释系统为什么要把统计看板和核心业务数据隔离。文章不要写成业务推广&#xff0c; 而要写清楚&#xff1a;页面加载读小快照&#xff0c;刷新动作走明确…

作者头像 李华
网站建设 2026/6/23 19:02:17

上下文窗口与长上下文问题

理解长上下文&#xff0c;最关键是区分 prefill 和 decode。Prefill&#xff1a;模型先把整段已有上下文都读一遍&#xff0c;为每一层生成 K/V 状态。上下文越长&#xff0c;prefill 通常越重&#xff0c;TTFT&#xff08;首 token 延迟&#xff09;越高。Decode&#xff1a;之…

作者头像 李华
网站建设 2026/6/23 18:56:23

医院查不出毛病却浑身难受?45岁姐姐的真实改变

我差点以为自己得了什么怪病前两年&#xff0c;我总感觉喘不上气&#xff0c;胸口像压了块石头。去中医院&#xff0c;大夫说我气虚&#xff1b;又去综合医院做各种检查&#xff0c;心脏彩超、心电图都做了&#xff0c;西医说心脏有点供血不足&#xff0c;但不算严重。开了中药…

作者头像 李华