wordpress简洁模板/seo优化在线
前言1:这篇博客仅限于介绍拉格朗日乘子法,KKT条件,ALM算法,ADMM算法等最优化方法的使用以及简版代码实现,但不会涉及具体的数学推导;不过在下面我会给出具体数学推导的相关文章和截图,供学有余力的同志参考;
前言2:从OSQP求解器的官方网站可以得知,OSQP求解器使用的最优化方法即ADMM算法;
a
a
a
a
a
a
1. 拉格朗日乘子法与KKT条件
注:这一章节不从数学推导上,而是从实际数学意义上,直观的讲解拉格朗日乘子法和KKT条件是如何推导得来的;
1.1 无约束的优化问题 -- 梯度下降法
首先从无约束的优化问题讲起,一般就是要使表达式 取到最小值;对于这类问题在高中就学过怎么做,只要对它的每一个变量求导,然后让偏导为零,解方程组就行了;
在极值点处一定满足 (只是必要条件),然后对它进行求解,再代入验证是否真的是极值点就行了;
但是有很多问题通过直接求导是解不出来的,或者很难解,所以就需要梯度下降法、牛顿法、坐标下降法之类的数值迭代算法;对于这些迭代算法就像下面这张图一样,我们希望找到其中的最小值,一个比较直观的想法是先找一个起点,然后不断向最低点靠近。就先把一个小球放到一个碗里一样;
一开始要找一个起始点,然后确定走的方向和距离,最后还要知道什么时候停止;这三步中最难的是确定走的方向,走的慢点还可以接受,要是方向错了就找不到最小值了;
- 走的距离可以简单的设为一个比较小的值;
- 起始点可以随机选一个
;
- 关键是方向,可以选择
处的梯度的反方向,这是函数在这个点下降最快的方向;
- 最终的停止条件是梯度的大小很接近于 0(在极值点处的梯度大小就是 0);
这种方法依靠梯度确定下降方向的方法叫做梯度下降法;
对 求极小值的流程:
- 随机选定起点
- 得到函数在
的梯度,然后从
向前走一步(
)
- 重复第2步,直到梯度接近于0(小于一个事先设定的小值),或到达指定的迭代次数上限
1.2 有约束优化问题 -- 拉格朗日乘子法和KKT条件
摘自文章:
- https://www.cnblogs.com/xinchen1111/p/8804858.html
- 什么是仿射函数?-CSDN博客
- https://www.cnblogs.com/fuleying/p/4481334.html
a
a
1.2.1 单个等式约束
我们可能要在满足一定约束条件的情况下最小化目标函数,比如有一个等式约束:
如图,其中的圆圈是目标函数 𝑓(𝑥,𝑦) 投影在平面上的等值线,黑线是约束条件 ℎ(𝑥)=0 的函数图像;等值线与函数图像相交的点其实就是所有满足约束的点;
那么极值点只有可能在等值线与函数图像相切的地方取到,因为如果在相交的地方取到,那么沿着 ℎ(𝑥) 的图像往前走或者往后走,一定还有其它的等值线与它相交,也就是 𝑓(𝑥,𝑦) 的值还能变大和变小,所以交点不是极值点,只有相切的时候才有可能是极值点(不可能同时变大和变小,往前后两个方向走只能同时变大/变小,这才是极值点);
在相切的地方 ℎ(𝑥) 的梯度和 𝑓(𝑥,𝑦) 的梯度应该是在同一条直线上的(在切点处两个函数的梯度都与切平面垂直,所以在一条直线上);
所以满足条件的极值点一定满足:∇𝑓(𝑥,𝑦)=𝜆∇ℎ(𝑥,𝑦) 和 ℎ(𝑥,𝑦)=0
那么只要解出这个方程组,就可以得到问题的解析解了;当然也存在解不出来的情况,就需要用罚函数法之类的方法求数值解了;
为了方便和好记,就把原来的优化问题写成 𝑓(𝑥,𝑦)+𝜆ℎ(𝑥,𝑦) 的形式,然后分别对 𝜆,𝑥,𝑦 求偏导,并且令偏导为 0 就行了(对 x,y 的偏导为0可以得到式子 ∇𝑓(𝑥,𝑦)-𝜆∇ℎ(𝑥,𝑦)=0 )( 对 𝜆 的偏导为0可以得到式子 ℎ(𝑥,𝑦)=0 ),和之前得到的方程组是一样的;这种方法叫拉格朗日乘数法;
a
a
1.2.2 多个等式约束
将拉格朗日乘子法扩展到含有多个等式约束的情况:
这里的平面和球面分别代表了两个约束 ℎ1(𝑥) 和 ℎ2(𝑥),那么这个问题的可行域就是它们相交的那个圆;这里蓝色箭头表示平面的梯度,黑色箭头表示球面的梯度,那么相交的圆的梯度就是它们的线性组合,所以在极值点处目标函数的梯度和约束的梯度的线性组合在一条直线上,所以满足:
为了好记,将原来的约束的问题写成 的形式,然后对 𝑥、𝜆 求偏导,让它们为 0;结果像上面一样直接列方程组是一样的,这可以看做是一种简记,或者是对偶问题,这个函数叫做拉格朗日函数;
a
a
1.2.3 同时含有等式约束和不等式约束
如果问题中既有等式约束,又有不等式约束怎么办呢?对于:
当然也同样约定不等式是 ≤,如果是 ≥ 只要取反就行了;
对于这个问题先不看等式约束,对于不等式约束和目标函数的图:
阴影部分就是可行域,也就是说可行域从原来的一条线变成了一块区域;那么能取到极值点的地方可能有两种情况:
- 还是在 ℎ(𝑥) 和 等值线相切的地方
- 𝑓(𝑥) 的极值点本身就在可行域里面
因为如果不是相切,那么同样的,对任意一个在可行域中的点,如果在它附近往里走或者往外走,𝑓(𝑥) 一般都会变大或者变小,所以绝大部分点都不会是极值点;除非这个点刚好在交界处,且和等值线相切;或者这个点在可行域内部,但是本身就是 f(x)𝑓(𝑥) 的极值点;
对于第一种情况,不等式约束就变成等式约束了,对 𝑓(𝑥)+𝜆ℎ(𝑥)+𝜇𝑔(𝑥) 用拉格朗日乘子法:
对于第二种情况,不等式约束就相当于没有,对 𝑓(𝑥)+𝜆ℎ(𝑥) 用拉格朗日乘子法:
把两种情况用同一组方程表示出来,对比一下两个问题:
- 第一种情况中有 𝜇≥0 且 𝑔(𝑥)=0
- 第二种情况 𝜇=0 且 𝑔(𝑥)≤0
综合两种情况,可以写成 𝜇𝑔(𝑥)=0 且 𝜇≥0 且 𝑔(𝑥)≤0:
这个就是 KKT 条件;它的含义是这个优化问题的极值点一定满足这组方程组(不是极值点也可能会满足,但是不会存在某个极值点不满足的情况);它也是原来的优化问题取得极值的必要条件,解出来了极值点之后还是要代入验证的,但是因为约束比较多,情况比较复杂,KKT 条件并不是对于任何情况都是满足的;
要满足 KKT 条件需要有一些规范性条件(Regularity conditions),就是要求约束条件的质量不能太差,常见的比如:
- LCQ:如果 ℎ(𝑥) 和 𝑔(𝑥) 都是形如 𝐴𝑥+𝑏 的仿射函数,那么极值一定满足 KKT 条件;
- LICQ:起作用的 𝑔(𝑥) 函数(即 𝑔(𝑥) 相当于等式约束的情况)和 ℎ(𝑥) 函数在极值点处的梯度要线性无关,那么极值一定满足 KKT 条件;
- Slater 条件:如果优化问题是个凸优化问题,且至少存在一个点满足 ℎ(𝑥)=0 和 𝑔(𝑥)=0,极值一定满足 KKT 条件,并且满足强对偶性质;
a
a
a
a
a
a
2. ALM 算法
注1:ALM(Augmented Lagrange Multiplier)算法,即增广型拉格朗日乘子法
注2:ALM 算法常用于线性规划问题( 不能有高阶项/根号项,也不能有两个变量之间的交乘积项);
注3:ALM 算法的推导过程 -- http://faculty.bicmr.pku.edu.cn/~wenzw/optbook/lect/16-lect-alm.pdf
2.1 ALM 算法介绍
只考虑含有等式约束的问题:
a
a
注:含有不等式约束问题的 ALM 算法,见文章 -- http://faculty.bicmr.pku.edu.cn/~wenzw/optbook/lect/16-lect-alm.pdf
构造增广拉格朗日函数:
:拉格朗日乘子(矩阵)
:惩罚项权重(标量)
a
a
注意:增广拉格朗日乘子法就是在拉格朗日乘子法获得的函数后面,加上针对所有等式约束的惩罚项;
a
a
优点:
- 原拉格朗日函数的收敛性不太好,抖动很大不稳定;
- 加上了惩罚项可以增加原拉格朗日函数的凸性,使得我们可以通过更简单的方法,如梯度下降法去求解这个函数的最优解;
- 加强了等式约束的限制作用(针对等式约束增加了惩罚项),使得在迭代的过程中迭代点一直是在约束附近的区域进行梯度下降,不会跑太远,从而加快了求解速度;
ALM 算法的求解过程:梯度下降
- 先对变量
进行梯度下降:
- 再对拉格朗日乘子
进行梯度下降:
- 上述两步为一次迭代,不断这样迭代下去,直至收敛或者到达指定迭代次数;
2.2 ALM 算法代码示例
举例:只含等式约束
a
使用 Scipy 中的函数 linprog 求解线性规划问题,将求解得到的结果作为参考答案:
函数 linprog:scipy.optimize.linprog函数参数最全详解_optimize的linprog-CSDN博客
"""
solve the following problem with scipy
min f(x) = -3x[0] - 5x[1]
s.t. x[0] + x[2] = 42x[1] + x[3] = 123x[0] + 2x[1] + x[4] = 18x[0], x[1], x[2], x[3], x[4] >= 0optimal solution:
fun: -36.0
x: [ 2.000e+00 6.000e+00 2.000e+00 0.000e+00 0.000e+00]
"""from scipy.optimize import linprog
import torchc = torch.tensor([-3, -5, 0, 0, 0], dtype=torch.float32)
A = torch.tensor([[1, 0, 1, 0, 0], [0, 2, 0, 1, 0], [3, 2, 0, 0, 1]], dtype=torch.float32)
b = torch.tensor([4, 12, 18], dtype=torch.float32)res = linprog(c, A_eq=A, b_eq=b, bounds=(0, None))
print(res)
a
ALM 算法示例:
"""
solve the following problem with Augmented Lagrange Multiplier method
min f(x) = -3x[0] - 5x[1]
s.t. x[0] + x[2] = 42x[1] + x[3] = 123x[0] + 2x[1] + x[4] = 18x[0], x[1], x[2], x[3], x[4] >= 0问题形式:
min f(x) = c^T x
s.t. Ax = b
x >= 0
"""import torchdef lagrangian_function(x, lambda_):return f(x) + lambda_ @ (A @ x - b) + alpha / 2 * ((A @ x - b)**2).sum()def f(x):return c @ xdef update_x(x, lambda_):""" update x with gradient descent """lagrangian_function(x, lambda_).backward()new_x = x - eta * x.gradx.data = new_x.clamp(min=0)x.grad.zero_()def update_lambda(lambda_):new_lambda = lambda_ + alpha * (A @ x - b)lambda_.data = new_lambdadef pprint(i, x, lambda_):print(f'\n{i+1}th iter, L:{lagrangian_function(x, lambda_):.2f}, f: {f(x):.2f}')print(f'x: {x}')print(f'lambda: {lambda_}')print("constraints violation: ")print(A @ x - b)def solve(x, lambda_):for i in range(500):pprint(i, x, lambda_) # 更新 xupdate_x(x, lambda_) # 更新拉格朗日乘子update_lambda(lambda_) # 打印信息if __name__ == '__main__':eta = 0.03 # 学习率alpha = 1 # 惩罚权重c = torch.tensor([-3, -5, 0, 0, 0], dtype=torch.float32)A = torch.tensor([[1, 0, 1, 0, 0], [0, 2, 0, 1, 0], [3, 2, 0, 0, 1]], dtype=torch.float32)b = torch.tensor([4, 12, 18], dtype=torch.float32)lambda_ = torch.tensor([0, 0, 0], dtype=torch.float32)x = torch.tensor([2, 0, 2, 0, 0], dtype=torch.float32, requires_grad=True)solve(x, lambda_)
a
a
a
a
a
a
3. ADMM 算法
注1:ADMM(Alternating Direction Method of Multipliers)算法,即交替方向乘子法
注2:关于详细的数学推导 -- 一文详解从拉格朗日乘子法、KKT条件、对偶上升法到罚函数与增广Lagrangian乘子法再到ADMM算法(交替方向乘子法)_拉格朗日乘子 二次惩罚系数-CSDN博客
3.1 ADMM 算法介绍
只考虑含有等式约束的问题:
a
a
和ALM算法的不同点在于:将所有的变量分成几部分(假设为两部分,一部分是向量
,一部分是向量
),然后分别进行梯度下降,而不是一次性将所有的变量全部都进行梯度下降;
构造增广拉格朗日函数:
:拉格朗日乘子(矩阵)
:惩罚项权重(标量)
ADMM 算法的求解过程:
- 先对变量
进行梯度下降:
- 再对变量
进行梯度下降:
- 再对变量
进行梯度下降:
- 上述三步为一次迭代,不断这样迭代下去,直至收敛或者到达指定迭代次数;
3.2 ADMM 算法代码示例
"""
solve the following problem with Alternating Direction Multiplier Method
min f(x) = -3x[0] - 5x[1]
s.t. x[0] + x[2] = 42x[1] + x[3] = 123x[0] + 2x[1] + x[4] = 18x[0], x[1], x[2], x[3], x[4] >= 0问题形式:
min f(x) = c^T x
s.t. Ax = b
x >= 0
"""import torchdef lagrangian_function(x, lambda_):return f(x) + lambda_ @ (A @ x - b) + alpha / 2 * ((A @ x - b)**2).sum()def f(x):return c @ xdef update_x(x, lambda_):""" update x with gradient descent """for i in range(len(x)):# not the best way to calculate gradient# 这里直接将所有的变量拆成了5份,这并不是最好的求解方式lagrangian_function(x, lambda_).backward()x_i = x[i] - eta * x.grad[i]x.data[i] = max(0, x_i)x.grad.zero_()def update_lambda(lambda_):new_lambda = lambda_ + alpha * (A @ x - b)lambda_.data = new_lambdadef pprint(i, x, lambda_):print(f'\n{i+1}th iter, L:{lagrangian_function(x, lambda_):.2f}, f: {f(x):.2f}')print(f'x: {x}')print(f'lambda: {lambda_}')print("constraints violation: ")print(A @ x - b)def solve(x, lambda_):for i in range(500):pprint(i, x, lambda_)update_x(x, lambda_)update_lambda(lambda_)if __name__ == '__main__':eta = 0.03 # 学习率alpha = 1 # 惩罚权重c = torch.tensor([-3, -5, 0, 0, 0], dtype=torch.float32)A = torch.tensor([[1, 0, 1, 0, 0], [0, 2, 0, 1, 0], [3, 2, 0, 0, 1]], dtype=torch.float32)b = torch.tensor([4, 12, 18], dtype=torch.float32)lambda_ = torch.tensor([0, 0, 0], dtype=torch.float32)x = torch.tensor([2, 0, 2, 0, 0], dtype=torch.float32, requires_grad=True)solve(x, lambda_)
相关文章:
笔记101:OSQP求解器的底层算法 -- ADMM算法
前言1:这篇博客仅限于介绍拉格朗日乘子法,KKT条件,ALM算法,ADMM算法等最优化方法的使用以及简版代码实现,但不会涉及具体的数学推导;不过在下面我会给出具体数学推导的相关文章和截图,供学有余力…...

Java银系统/超市收银系统/智慧新零售/ERP进销存管理/线上商城/h5/小程序
>>>系统简述: 神点收银系统支持B2B2C多商户模式,系统基于前后端分离的架构,后端采用Java SpringBoot Mysql Mybatis Plus,前端基于当前流行的Uniapp、Element UI,支持小程序、h5。架构包含:会员端…...

大学网页制作作品1
作品须知:1.该网页作品预计分为5个页面(其中1个登录页面,1个首页主页面,3个分页面),如需要可自行删改增加页面。(总共约800行html,1200行css,100行js) 2.此网页源代码只用于学习和模…...

【会议征稿,IEEE出版】第三届机器人、人工智能与智能控制国际会议(RAIIC 2024,7月5-7)
第三届机器人、人工智能与智能控制国际会议(RAIIC 2024)将于2024年7月5-7日中国绵阳举行。 RAIIC 2024是汇聚业界和学术界的顶级论坛,会议将邀请国内外著名专家就以传播机器人、人工智能与智能控制领域的技术进步、研究成果和应用做专题报告…...

离线部署OpenIM
目录 1.提取相关安装包和镜像 2.安装docker和docker-compose 3.依次导入镜像 4.解压安装包 5.执行安装命令 6.PC Web 验证 7.开放端口 7.1IM 端口 7.2Chat 端口 7.3 PC Web 及管理后台前端资源端口 “如果您在解决类似问题时也遇到了困难,希望我的经验分享…...

sql:between and日期毫秒精度过多导致的查询bug
复现 一般情况下,前端传的日期值大多都是yyyy-MM-dd HH:mm:ss(标准格式),比如2024-06-25 10:49:50,但是在测试环境,测试人员测出了一个带毫秒的日期:比如2024-06-25 10:49:50.9999999 这种情况下会出现查询bug SELEC…...

【日常记录】【JS】优雅检测用户是否在指定元素的外部点击
文章目录 1、界面基本布局2、代码实现3、参考链接 1、界面基本布局 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">…...

MySQL 5.7.42 主从复制环境搭建
MySQL 5.7.42 主从复制环境搭建 下载MySQL二进制包操作系统环境配置安装过程搭建从库 本次安装环境: OS版本:Red Hat Enterprise Linux Server release 6.8 (Santiago) MySQL版本:5.7.42 架构:同一台机器,多实例安装搭…...

【Excel】单元格如何设置可选项、固定表头
设置可选项 固定表头:视图---冻结窗口...

大模型ReAct:思考与工具协同完成复杂任务推理
ReAct: Synergizing Reasoning and Acting in Language Models Github:https://github.com/ysymyth/ReAct 一、动机 人类的认知通常具备一定的自我调节(self-regulation)和策略制定(strategization)的能力࿰…...

深入了解银行核心账务系统及其测试的重要性
在数字化金融时代,银行的核心账务系统是保证银行业务稳定、安全运行的关键所在。这些系统,如核心账务系统、总账系统和财务会计管理系统,宛如银行的“中枢神经”,掌控着资金的流动和账务的处理。无论是存款、取款、贷款还是转账&a…...

实习公司内部OA系统项目经验
文章目录 前言一、请介绍一下你实习所做的项目?二、你觉得你项目的难点有哪些?三、你这个考勤打卡功能可以详细介绍一下吗1. 功能需求分析2. 系统设计与架构3. 数据库设计4. 具体实现5. 测试与优化四、Redis缓存技术用到哪里了请详细介绍一下1.应用场景2.缓存设计3.具体实现4…...

Ansys Zemax|在设计抬头显示器(HUD)时需要使用哪些工具?
附件下载 联系工作人员获取附件 汽车抬头显示器或汽车平视显示器,也被称为HUD,是在汽车中显示数据的透明显示器,不需要用户低头就能看到他们需要的重要资讯。这个名字的由来是由于该技术能够让飞行员在头部“向上”并向前看的情况下查看信息…...

Linux系统移动光标类命令
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...

Vitis Accelerated Libraries 学习笔记--Vision 库的组织结构
1. 简介 Vision 库的组织结构如下: ├── L1/ │ ├── README.md │ ├── examples/ │ ├── include/ │ ├── lib/ │ └── tests/ ├── L2/ │ ├── README.md │ ├── examples/ │ └── tests/ ├── L3/ │ ├── R…...

HTML+CSS 彩色浮雕按钮
效果演示 实现了一个彩色按钮特效,包括一个按钮(button)和一个前景色(::before)。按钮具有四种不同的颜色,当鼠标悬停在按钮上时,前景色会出现渐变效果,并且按钮的颜色、文本阴影和边…...

ChatBI开源实现: 基于SuperSonic的AI+BI的产品设计
产品起源 为什么要做这样的产品?文章《ChatBI开源实现: AIBI的产品设计》中有介绍 为什么要自己做这样的产品?1、低成本试错;2、未来数据生态入口; 为什么要基于Supersonic做? 开源协议友好:可魔改商用 社区…...

【嵌入式Linux】i.MX6ULL 外部中断服务函数的初始化
文章目录 1. Cortex-A7 中断系统1.1 分析1.2 具体处理流程 2. 外部中断服务函数的初始化2.1 基本流程分析2.2 具体代码分析2.2.1. 定义中断处理类型和结构体2.2.2. 初始化中断系统2.2.3. 注册中断处理函数2.2.4. 具体的中断处理逻辑2.2.5. 默认的中断处理函数 3. 完整代码 本文…...

线性代数、矩阵计算
一、线性代数 1、对于向量,若a是标量,为a的绝对值乘以b的向量长度。 2、点乘 3、范数:向量或者矩阵的长度 L1范数:(对向量)每个元素的绝对值求和 L2范数:(对向量)torch.…...

PostgreSQL 高级功能(五)
1. 存储过程与函数 1.1 创建存储过程 存储过程是一组预编译的SQL语句,可以简化复杂的操作。以下是一个简单的存储过程示例: CREATE OR REPLACE FUNCTION add_user(username VARCHAR, email VARCHAR) RETURNS VOID AS $$ BEGININSERT INTO users (use…...

食品企业仓储式批发零售一体化解决方案
食品企业需要有效应对日益复杂的市场挑战和消费者需求的快速变化的挑战并提升市场竞争力,仓储式类的批发零售一体化需求应运而生。这一全新的商业模式不仅整合了传统的批发和零售模式,还优化了供应链管理和客户体验,成为食品行业发展的新引擎…...

chrome插件,修改对应URL的http请求的header头,包括ajax请求
要创建一个可以灵活修改HTTP请求头的Chrome扩展,包括一个用户界面来动态设置头部名称和值,可以按照以下步骤进行。我们会用到 chrome.storage API 来保存用户的设置,并在后台脚本中使用这些设置来修改请求头。 文件结构 my_chrome_extensio…...

C语言 | Leetcode C语言题解之第191题位1的个数
题目: 题解: int hammingWeight(uint32_t n) {int ret 0;while (n) {n & n - 1;ret;}return ret; }...

【C++11(二)】lambda表达式和可变参数模板
一、可变参数模板 C11的新特性可变参数模板 能够让您创建可以接受 可变参数的函数模板和类模板 // Args是一个模板参数包,args是一个函数形参参数包 // 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。 template <class ...Arg…...

昇思25天学习打卡营第2天|张量Tensor
张量Tensor 创建张量张量的属性张量索引张量运算 稀疏张量 总结 简单讲讲张量,数学和物理学界以一种方式定义张量,机器学习上则是以另一种方式定义张量,这里的张量也与神经网络联系紧密,神经网络需要进行大量的数学计算࿰…...

[leetcode]valid-triangle-number. 有效三角形的个数
. - 力扣(LeetCode) class Solution { public:int triangleNumber(vector<int>& nums) {int n nums.size();sort(nums.begin(), nums.end());int ans 0;for (int i 0; i < n; i) {for (int j i 1; j < n; j) {int left j 1, righ…...

java SQL server 多实例的情况
而对于java,对付多个数据库实例就有些要注意的了: 首先,同样连接字符串上加上“\实例名”: jdbc:sqlserver://127.0.0.1\\mssqlserver2008;DatabaseNameLPT; 此处应去掉端口1433。因为连接数据库自命名实例的url中没有端口号1433…...

html--404页面
<!DOCTYPE html> <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <meta http-equiv"X-UA-Compatible" content"IEedge,chrome1"> <title>404 错误页面不存在&…...

[word] Word如何删除所有的空行? #职场发展#学习方法
Word如何删除所有的空行? 很多网友从网页复制文字粘贴到word文档后发现段落之间有空行,如果文字不多,手动删除这些空行也没有多少工作量,但是如果文字的字数达到成千上万,一个个手动删除这些空行还是很繁琐的。那么&a…...

【CSS】深入探讨 CSS 的 `calc()` 函数
深入探讨 CSS 的 calc() 函数 calc() 是一个 CSS 函数,用于在样式表中进行数学计算,从而动态地设置 CSS 属性值。它允许开发者在指定长度、百分比、数值等时,进行加减乘除运算。通过 calc() 函数,我们可以实现更灵活和响应式的设…...