当前位置: 首页 > article >正文

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)

目录

🔍 若用递归计算每一项,会发生什么?

Horner's Rule(霍纳法则)

 第一步:我们从最原始的泰勒公式出发

第二步:从形式上重新观察展开式 

🌟 第三步:引出霍纳法则(Horner’s Rule)

 第四步:如何用这个结构重写泰勒展开式? 

完整代码

 从迭代转换成递归逻辑

“迭代”和“循环” 


当前递归方法的结构回顾:

double num = 1, den = 1;double taylor(int n, double x) {if (n == 0) return 1;double res = taylor(n - 1, x);  // 一次函数调用num *= x;                       // 分子:一次乘法den *= n;                       // 分母:一次乘法return res + num / den;
}

这一版已经做了初步优化:我们通过 累计 num 和 den 来避免重复调用 pow(x,n)factorial(n)

但这只是相对优化,我们现在要分析:

🔍 若用递归计算每一项,会发生什么?

我们从第 0 项到第 n 项共计算 n+1项,每一项的乘法成本如下:

第 k 项乘法次数
k = 00
k = 11
k = 22
......
k = nn

所以总乘法次数为:

✅ 因此,乘法总次数为 O(n^2)!

🚨 问题在哪里?

  • 你对每一项都重新计算幂和阶乘

  • 导致重复计算,浪费大量 CPU 时间

  • 如果你希望 n = 50n = 100,程序变慢得很明显

🤔 有没有更好的方式?

是的。你就引出了今天的主角:

Horner's Rule(霍纳法则)

我们可以尝试换一种展开方式,让我们不必每次都分别去计算幂和阶乘。

我们将展开式进行重写:

也就是一种嵌套式计算结构。

这个就是 Horner 法则的思路 —— 逐层乘进去、逐层加出来,避免重复乘法和幂展开。


 第一步:我们从最原始的泰勒公式出发

以 e^x 为例,泰勒展开是:

 

这表达得很清晰,每一项结构都类似:

  • 分子是 x^k

  • 分母是 k!

所以直觉上,我们就写了:

double num = 1;  // 分子
double den = 1;  // 分母double taylor(int n, double x) {if (n == 0) return 1;               // 1️⃣ 锚点:停止递归double res = taylor(n - 1, x);      // 2️⃣ 先构造前面所有项的和num *= x;                           // 3️⃣ 然后再更新状态den *= n;return res + num / den;             // 4️⃣ 当前项加进去
}

 递归方法的思路解析,可以看我之前发表的文章:

数据结构:递归:泰勒展开式(Taylor Series Expansion)-CSDN博客

 但是整个算法需要 O(n^2) 次的乘法。

于是我们问自己:

❓有没有一种办法,我们不显式地计算幂和阶乘,而是用一种更聪明的方式重写它?

第二步:从形式上重新观察展开式 

我们把:

我们尝试反向收敛:

从最后一项往前看。 

设:

假设我们已知最后一项是:

我们问:有没有可能构造出一个结构:

 

我们知道这种结构是逐层“乘进去再加”,是一种“嵌套结构”。

这时候,你会自然联想到:


🌟 第三步:引出霍纳法则(Horner’s Rule)

Horner's Rule 是一种重写多项式的方式,使其变成嵌套乘加结构,从而节省乘法次数。

给你一个多项式:

它可以等价重写成:

 

第一步:从最后一项开始反向思考 

先写出最后一项:

但我们不这么直接展开,而是尝试合并每一项,构建嵌套结构。我们回顾一下: 

第二步:尝试因式提取,构造嵌套结构 

我们从最后一项往回包,先只保留最后一项:

向前一项加:

 再加:

 最后加 1 项:

第三步:得出结论(形式)

最终你得到的就是:

 

这就是 Horner 法则在泰勒展开中的精确结构! 

 


 第四步:如何用这个结构重写泰勒展开式? 

霍纳法则告诉我们:

如果你有一个嵌套表达式,它从最深处开始乘加,就可以从最后一项反向累积计算

我们的目标是以某种结构计算它,让乘法次数最少。 

观察这个嵌套结构你会发现:

  • 每一层都包含一个 “1 + x / k * (之前的结果)”

  • 最里面的是 1

  • 然后不断被 x/k 包裹

它是一个“逐层包裹”的结构,每一层是:

 这说明我们可以从“最深的那一层”开始往外展开。

于是你意识到这就是一种“右折叠(right fold)”,即:

result = 1;
result = 1 + x * result / 4;
result = 1 + x * result / 3;
result = 1 + x * result / 2;
result = 1 + x * result / 1;

 从后往前包,每次乘进去一个 x / i,再加 1。

所谓「右折叠」就是我们从表达式的最右边开始构建,逐层包起来。 

1 + x/4              ← 第 1 层(最里面)
1 + x/3 * (1 + x/4)  ← 第 2 层
1 + x/2 * (...)      ← 第 3 层
1 + x/1 * (...)      ← 第 4 层

你看到一种非常明显的重复:

每次的操作是:

result = 1 + x * result / i;

从哪个 i 开始?

  • 最深一层是对应最大项 n

  • 然后是 n - 1

  • 最后是 i = 1

所以你会写一个反向的循环:

for (int i = n; i > 0; --i)

初始值设置为:

double result = 1.0;  // 最里层的恒定值

为什么是 1.0?

因为你可以认为最内层就是 1 + 0,也就是我们从最后一项 x^n / n! 折叠得到的值是最深的那个 1,逐层向外构建。

完整代码

double horner_taylor(int n, double x) {double result = 1.0;                  // 最深嵌套项for (; n > 0; n--) {                 // 从内往外迭代result = 1 + x * result / n;     // 每次构造一层}return result;
}

 从迭代转换成递归逻辑

递归的本质是:

用一个函数在每一层调用自己,把循环变成函数调用链。

从上面的迭代式:

你可以直接转换成递归表达式:

double horner_recursive(int n, double x) {static double result = 1.0;if (n == 0) return result;       // 最深嵌套项(base case)result = 1 + x / n * result;  return horner_recursive(n - 1, x);   
}

循环版结构递归版结构
从 n 逐步降到 1从 n 递归到 0(递归终止条件)
每次更新 result = ...每次返回 1 + x * 下层 / n
初始 result = 1.0horner_recursive(0, x) = 1.0

两者实际上是完全等价的计算结构。


“迭代”“循环” 

什么是“循环”(loop)?

  • 循环是语法结构

  • 是编程语言提供的控制流语句(forwhiledo-while

  • 它的作用是:重复执行某段代码

比如:

for (int i = 0; i < 10; ++i) {// 执行 10 次
}

什么是“迭代”(iteration)?

  • 迭代是算法行为

  • 意思是:基于前一个结果,不断构造下一个结果

  • 它不依赖一定要用循环语法,也可以用递归实现!

举例说明:

✅ 迭代行为 + 循环实现

double result = 1;
for (int i = n; i > 0; --i)result = 1 + x * result / i;
  • 每一轮基于上一轮的 result

  • 所以这是一个迭代算法

  • 同时用了 for,所以也是一个循环结构

 ✅ 迭代行为 + 递归实现

double horner_recursive(int n, double x) {static double result = 1.0;if (n == 0) return result;       // 最深嵌套项(base case)result = 1 + x / n * result;  return horner_recursive(n - 1, x);   
}
  • 每一层基于“下一层”的结果

  • 所以也是一种迭代算法

  • 但这次用的是递归结构

 🚫 循环 ≠ 迭代(反例)

for (int i = 0; i < 10; ++i) {cout << "Hello\n";
}
  • 这使用了循环,但没有迭代行为(没有前后状态依赖)

  • 所以它是循环,但不是迭代

相关文章:

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)

目录 &#x1f50d; 若用递归计算每一项&#xff0c;会发生什么&#xff1f; Horners Rule&#xff08;霍纳法则&#xff09; 第一步&#xff1a;我们从最原始的泰勒公式出发 第二步&#xff1a;从形式上重新观察展开式 &#x1f31f; 第三步&#xff1a;引出霍纳法则&…...

医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor

1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...

跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践

在电商行业蓬勃发展的当下&#xff0c;多平台运营已成为众多商家的必然选择。然而&#xff0c;不同电商平台在商品数据接口方面存在差异&#xff0c;导致商家在跨平台运营时面临诸多挑战&#xff0c;如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...

电脑桌面太单调,用Python写一个桌面小宠物应用。

下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡&#xff0c;可以响应鼠标点击&#xff0c;并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...

字符串哈希+KMP

P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!

今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等&#xff0c;设置经线、纬线都以10间隔显示。 2、需要插入背会归线&#xf…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

从实验室到产业:IndexTTS 在六大核心场景的落地实践

一、内容创作&#xff1a;重构数字内容生产范式 在短视频创作领域&#xff0c;IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色&#xff0c;生成的 “各位吴彦祖们大家好” 语音相似度达 97%&#xff0c;单条视频播放量突破百万…...

boost::filesystem::path文件路径使用详解和示例

boost::filesystem::path 是 Boost 库中用于跨平台操作文件路径的类&#xff0c;封装了路径的拼接、分割、提取、判断等常用功能。下面是对它的使用详解&#xff0c;包括常用接口与完整示例。 1. 引入头文件与命名空间 #include <boost/filesystem.hpp> namespace fs b…...

小智AI+MCP

什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析&#xff1a;AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github&#xff1a;https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...

Python爬虫实战:研究Restkit库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...

轻量级Docker管理工具Docker Switchboard

简介 什么是 Docker Switchboard &#xff1f; Docker Switchboard 是一个轻量级的 Web 应用程序&#xff0c;用于管理 Docker 容器。它提供了一个干净、用户友好的界面来启动、停止和监控主机上运行的容器&#xff0c;使其成为本地开发、家庭实验室或小型服务器设置的理想选择…...

如何通过git命令查看项目连接的仓库地址?

要通过 Git 命令查看项目连接的仓库地址&#xff0c;您可以使用以下几种方法&#xff1a; 1. 查看所有远程仓库地址 使用 git remote -v 命令&#xff0c;它会显示项目中配置的所有远程仓库及其对应的 URL&#xff1a; git remote -v输出示例&#xff1a; origin https://…...

Linux基础开发工具——vim工具

文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...

echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式

pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图&#xff0c;如果边框加在dom上面&#xff0c;pdf-lib导出svg的时候并不会导出边框&#xff0c;所以只能在echarts图上面加边框 grid的边框是在图里…...

goreplay

1.github地址 https://github.com/buger/goreplay 2.简单介绍 GoReplay 是一个开源的网络监控工具&#xff0c;可以记录用户的实时流量并将其用于镜像、负载测试、监控和详细分析。 3.出现背景 随着应用程序的增长&#xff0c;测试它所需的工作量也会呈指数级增长。GoRepl…...

麒麟系统使用-进行.NET开发

文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的&#xff0c;如果需要进行.NET开发&#xff0c;则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET&#xff0c;所以要进…...

游戏开发中常见的战斗数值英文缩写对照表

游戏开发中常见的战斗数值英文缩写对照表 基础属性&#xff08;Basic Attributes&#xff09; 缩写英文全称中文释义常见使用场景HPHit Points / Health Points生命值角色生存状态MPMana Points / Magic Points魔法值技能释放资源SPStamina Points体力值动作消耗资源APAction…...

GraphRAG优化新思路-开源的ROGRAG框架

目前的如微软开源的GraphRAG的工作流程都较为复杂&#xff0c;难以孤立地评估各个组件的贡献&#xff0c;传统的检索方法在处理复杂推理任务时可能不够有效&#xff0c;特别是在需要理解实体间关系或多跳知识的情况下。先说结论&#xff0c;看完后感觉这个框架性能上不会比Grap…...

Canal环境搭建并实现和ES数据同步

作者&#xff1a;田超凡 日期&#xff1a;2025年6月7日 Canal安装&#xff0c;启动端口11111、8082&#xff1a; 安装canal-deployer服务端&#xff1a; https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...

【java面试】微服务篇

【java面试】微服务篇 一、总体框架二、Springcloud&#xff08;一&#xff09;Springcloud五大组件&#xff08;二&#xff09;服务注册和发现1、Eureka2、Nacos &#xff08;三&#xff09;负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...

HTTPS证书一年多少钱?

HTTPS证书作为保障网站数据传输安全的重要工具&#xff0c;成为众多网站运营者的必备选择。然而&#xff0c;面对市场上种类繁多的HTTPS证书&#xff0c;其一年费用究竟是多少&#xff0c;又受哪些因素影响呢&#xff1f; 首先&#xff0c;HTTPS证书通常在PinTrust这样的专业平…...

Python环境安装与虚拟环境配置详解

本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南&#xff0c;适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者&#xff0c;都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...

内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献

Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译&#xff1a; ### 胃肠道癌症的发病率呈上升趋势&#xff0c;且有年轻化倾向&#xff08;Bray等人&#xff0c;2018&#x…...

结构化文件管理实战:实现目录自动创建与归类

手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题&#xff0c;进而引发后续程序异常。使用工具进行标准化操作&#xff0c;能有效降低出错概率。 需要快速整理大量文件的技术用户而言&#xff0c;这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB&#xff0c;…...

云原生安全实战:API网关Envoy的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口&#xff0c;负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...

写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里

写一个shell脚本&#xff0c;把局域网内&#xff0c;把能ping通的IP和不能ping通的IP分类&#xff0c;并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...