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

3D数学系列之——再谈特卡洛积分和重要性采样

目录

  • 一、前篇文章回顾
  • 二、积分的黎曼和形式
  • 三、积分的概率形式(蒙特卡洛积分)
  • 四、误差
  • 五、蒙特卡洛积分计算与收敛速度
  • 六、重要性采样
  • 七、重要性采样方法和过程
  • 八、重要性采样的优缺点

一、前篇文章回顾

  在前一篇文章3D数学系列之——从“蒙的挺准”到“蒙的真准”解密蒙特卡洛积分!中,介绍了下面的这些朴素的公式:
灰色部分中点数总的点数≈灰色部分面积矩形面积⇒灰色部分面积≈矩形面积×灰色部分中点数总的点数\begin{align} & \cfrac{ 灰色部分中点数 } {总的点数} \approx \cfrac{灰色部分面积} {矩形面积} \\[2ex] & \Rightarrow 灰色部分面积 \approx 矩形面积 \times \cfrac{ 灰色部分中点数 } {总的点数} \end{align} 总的点数灰色部分中点数矩形面积灰色部分面积灰色部分面积矩形面积×总的点数灰色部分中点数

灰色部分面积≈矩形面积×P(P为点落在灰色部分的概率)灰色部分面积 \approx 矩形面积 \times P \quad (P为点落在灰色部分的概率) 灰色部分面积矩形面积×PP为点落在灰色部分的概率)

  虽然最终通过一个简单的概率乘法就可以计算出积分值,但是如何得到这个精确的概率值从而得到比较精确的积分值却不是那么简单的。并且这个方法直接用于计算或者说模拟计算来说,不确定的东西太多。下面我们就继续从积分的基本公式开始,讨论一下看看有没有进一步更形式化和更精确一点的方法。

二、积分的黎曼和形式

  对于数值积分计算来说,积分的黎曼和形式是最基本的形式:
∫abf(x)dx≈∑n=1Nf(xn)b−aN(1)\int \limits_a^b {f}(x) \mathrm{d} x \approx \sum \limits_{n=1}^N {f}(x_n) \cfrac{b-a}{N} \tag{1} abf(x)dxn=1Nf(xn)Nba(1)
  这是一个常见和基本的可以用于积分计算程序的基本公式。

三、积分的概率形式(蒙特卡洛积分)

  接着我们对黎曼和使用著名的”陶哲轩瞪眼法“进行观察。

  首先对于求和来说,第一项是 f(xn){f}(x_n)f(xn) ,这里我们一般会比较容易知道 f(x){f}(x)f(x) 的解析形式或者可以知道它的一些离散值。

  在实际计算中需要生成的是 xnx_nxn 的序列,这个序列是跟后面的 (b−a)N\cfrac{(b-a)}{N}N(ba) 紧密关联的,因为需要保证 xi−xi−1=b−aNx_{i}-x_{i-1} = \cfrac{b-a}{N}xixi1=Nbaxnx_nxn 序列是个等差数列,间隔是就是 (b−a)N\cfrac{(b-a)}{N}N(ba)

  这时,我们先打开思路,既然前一讲中已经可以通过随机变量的形式来计算积分,那么这时我们可不可以用一组随机数的序列来代替 xnx_nxn 的序列呢?

  既然讲到随机,那么回忆一下概率论中关于“均匀分布随机变量”的概率密度函数(The Probability Distribution Function,缩写为 PDF):
p(x)={1b−a,a<x<b0,其他(2)\mathrm{p}(x) = \begin{cases} \cfrac{1}{b-a}, \quad a \lt x \lt b \\[2ex] 0, \quad 其他 \end{cases} \tag{2} p(x)=ba1,a<x<b0,其他(2)
  接着我们用"陶哲轩瞪眼法"观察黎曼和公式与上面这个公式,此时我们应灵光乍现想到下面这样的形式:
∫abf(x)dx≈∑n=1Nf(xn)b−aN=1N∑n=1Nf(xn)×(b−a)根据乘以一个数等于除以一个数的倒数这个法则,有:=1N∑n=1Nf(xn)p(xn)(3)\int \limits_a^b {f}(x) \mathrm{d} x \approx \sum \limits_{n=1}^N {f}(x_n) \cfrac{b-a}{N} \\[2ex] = \cfrac{1}{N} \sum \limits_{n=1}^{N} {f}(x_n) \times (b-a) \\[2ex] 根据乘以一个数等于除以一个数的倒数这个法则,有: \\[2ex] = \cfrac{1}{N} \sum \limits_{n=1}^{N} \cfrac{{f}(x_n)}{\mathrm{p}(x_n)} \tag{3} abf(x)dxn=1Nf(xn)Nba=N1n=1Nf(xn)×(ba)根据乘以一个数等于除以一个数的倒数这个法则,有:=N1n=1Np(xn)f(xn)(3)
  啊哈!太好了,这一切看似是公式间的一种巧合或者说技巧性的,接着我们思考下它的意义。因为刚才我们已经说过原来的xnx_nxn 序列是个等差序列,本身就是均匀分布的,所以其概率密度函数(PDF)就是均匀分布变量的 PDF。如果我们取一个随机的 xnx_nxn 序列,并假设知道它的 PDF p(xn)\mathrm{p}(x_n)p(xn) 那么就可以根据上面这个式子的结果来计算积分值了。并且当 xnx_nxn 不断增多时,和 1N∑n=1Nf(xn)p(xn)\cfrac{1}{N} \sum \limits_{n=1}^{N} \cfrac{{f}(x_n)}{\mathrm{p}(x_n)}N1n=1Np(xn)f(xn) 也就越接近原始的积分值!这也就是传说中的蒙特卡洛积分的基本形式。它是合理且有意义的,起码我们不用只靠前一讲中的“蒙的真准”的方法了。需要注意的就是其中 f(xn)p(xn)\cfrac{{f}(x_n)}{p(x_n)}p(xn)f(xn) 项看上去虽然很奇怪,但他其实是有实际含义的,一般被称作概率平均。

  当然使用随机序列 xnx_nxn 是有条件的,即要求:
∫−∞+∞p(x)=1(4)\int \limits_{-\infty}^{+\infty} \mathrm{p}(x) = 1 \tag{4} +p(x)=1(4)
  接着我们继续观察(还是使用 “陶哲轩瞪眼法”)那个带有 PDF 的蒙特卡洛积分公式,发现其中还有个 1N\cfrac{1}{N}N1 , 这时我们应该突然明白其实这个式子还是个平均值的公式,而讲到平均值,学过概率论的同学就应该立刻想到“数学期望”。一般的数学期望的定义:
E[f(X)]=∑n=1∞f(xn)p(xn)E[{f}(X)] = \mathop{\sum}\limits_{n = 1}^{\infty} {f}(x_n) \mathrm{p}(x_n) E[f(X)]=n=1f(xn)p(xn)
  也就是说如果我们知道了随机变量 xnx_nxn 的随机 PDF: p(xn)\mathrm{p}(x_n)p(xn),那么随机变量函数的数学期望就可以用上式计算。当然如果 xnx_nxn 是连续的随机变量,那么就可以用积分形式来表示上面的表达式:
E[f(X)]=∫−∞+∞f(x)p(x)dxE[{f}(X)] = \mathop{\int}\limits_{-\infty}^{+\infty} {f}(x) \mathrm{p}(x) dx E[f(X)]=+f(x)p(x)dx
  这时,为了验证蒙特卡洛积分公式的正确性,我们来看看它的数学期望:
E(F(X))=E[1N∑n=1Nf(xn)p(xn)]=1N∑n=1N∫abf(x)p(x)×p(x)dx=1N∑n=1N∫abf(x)dx=∫abf(x)dxE(F(X)) = E \left[ \cfrac{1}{N} \sum \limits_{n=1}^{N} \cfrac{{f}(x_n)}{\mathrm{p}(x_n)} \right] \\[2ex] = \cfrac{1}{N} \sum \limits_{n=1}^{N} \int \limits_{a}^{b} \cfrac{{f}(x)}{\mathrm{p}(x)} \times \mathrm{p}(x) \mathrm{d}x \\[2ex] = \cfrac{1}{N} \sum \limits_{n=1}^{N} \int \limits_{a}^{b} {f}(x) \mathrm{d} x \\[2ex] = \int \limits_{a}^{b} {f}(x) \mathrm{d}x E(F(X))=E[N1n=1Np(xn)f(xn)]=N1n=1Nabp(x)f(x)×p(x)dx=N1n=1Nabf(x)dx=abf(x)dx
  这个结果简直太棒了!它说明蒙特卡洛积分公式的数学期望就是我们要求的积分值。这也间接的证明我们前面靠瞪眼法得到的公式本质上是正确的。或者说,蒙特卡洛积分的结果对于积分真值是无偏差的,也就是说是原积分的无偏估计。这个可以由“大数定理”来保证。只是不同的随机变量序列 xnx_nxn 会以不同的“速度”靠近积分原值。

四、误差

  按照数学家们的“尿性”,一定会严格的分析一下整个“蒙的挺准”的过程中的误差。既然刚才已经分析了蒙特卡洛积分的数学期望,那么继续根据概率论的知识,我们来分析下它的误差。一般对于随机序列来说,我们取其方差来评估其靠近真实值的程度。那么就让我们来计算下蒙特卡洛积分的方差:
σ2[Fn(X)]=σ2[1N∑n=1Nf(xn)p(xn)]=1N2∑n=1N∫ab(f(x)p(x)−E(Fn(X)))2×p(x)dx=1N[∫ab(f(x)p(x))2×p(x)dx−E(Fx(X))2]=1N[∫abf(x)2p(x)dx−E(Fn(X))2](5)\sigma^2[F_n(X)] \\[2ex] = \sigma^2 \left[ \cfrac{1}{N} \sum \limits_{n=1}^{N} \cfrac{f(x_n)}{\mathrm{p}(x_n)} \right] \\[2ex] = \cfrac{1}{N^2} \sum \limits_{n=1}^{N} \int \limits_a^b \left( \cfrac{f(x)}{\mathrm{p}(x)} - E(F_n(X)) \right)^2 \times \mathrm{p}(x) \mathrm{d}x \\[2ex] =\cfrac{1}{N}\left[ \int \limits_a^b \left( \cfrac{{f}(x)}{\mathrm{p}(x)} \right)^2 \times \mathrm{p}(x) \mathrm{d}x - E(F_x(X))^2 \right] \\[2ex] = \cfrac{1}{N} \left[ \int \limits_a^b \cfrac{{f}(x)^2}{\mathrm{p}(x)} \mathrm{d}x - E(F_n(X))^2 \right] \tag{5} σ2[Fn(X)]=σ2[N1n=1Np(xn)f(xn)]=N21n=1Nab(p(x)f(x)E(Fn(X)))2×p(x)dx=N1ab(p(x)f(x))2×p(x)dxE(Fx(X))2=N1abp(x)f(x)2dxE(Fn(X))2(5)
  上面最终包含了 1N\cfrac{1}{N}N1 项的最终的一堆公式,就是蒙特卡洛积分的方差,根据概率论的定义,其标准差就是方差的算术平方根。

  按照最终的证明结果,蒙特卡洛积分值与积分真实值之间的标准差(误差)有如下的形式:

误差∝1N(6)误差 \varpropto \cfrac{1}{\sqrt{N}} \tag{6} 误差N1(6)
  即最终误差正比于N的平方根的倒数。

五、蒙特卡洛积分计算与收敛速度

  有了前面这些数学知识的加持,那么我们就可以来看看用蒙特卡洛积分来计算积分时到底“速度”如何?

  其实看到这里,大家应该有个疑惑,我们费劲巴拉的推导了半天,到底在图个啥?

  那么如果你看了前一篇文章(3D数学系列之——从“蒙的挺准”到“蒙的真准”解密蒙特卡洛积分!),首先应该想到有了蒙特卡洛积分公式,我们是不是可以开始靠“蒙”来计算积分了?答案是肯定的,要计算蒙特卡洛积分,我们就需要产生一个随机变量的序列 xnx_nxn 并且需要知道其概率密度函数(PDF)p(xn)\mathrm{p}(x_n)p(xn) (有时候不需要知道 PDF 的表达式,只需要知道每个随机变量对应的概率值即可) 然后代入公式的右侧进行计算:
∫abf(x)dx≈1N∑n=1Nf(xn)p(xn)(3)\int \limits_a^b {f}(x) \mathrm{d} x \approx \cfrac{1}{N} \sum \limits_{n=1}^{N} \cfrac{{f}(x_n)}{\mathrm{p}(x_n)} \tag{3} abf(x)dxN1n=1Np(xn)f(xn)(3)
这样计算的好处是,我们可以用大一些(计算能力充足时)或者小一些(计算能力不足时)的随机变量序列来进行计算。

  当然这样计算的限制是,根据对蒙特卡洛方法标准差的计算,最终可以知道如果我们想提高计算精度一倍,那么差不多就需要将N提高4倍( 14=12\cfrac{1}{\sqrt{4}}=\cfrac{1}{2}41=21 ,即误差减小一半)。所以这就是平常所说的蒙特卡洛积分法收敛慢的根本原因。

  例如在我们关注的图形的光照积分估算过程中,这是个麻烦的问题,比如原先需要每个点采样1000条光线近似计算最终光照效果,要提高一倍精确度从而改进画质效果的话,那么每个点就需要采集4000条光线进行积分。因此,基本上现实中很少直接用蒙特卡洛积分的基本形式来求积分值的。

  所以最终这个结论是有点令人灰心丧气的,不过请继续往后看,这么好的方法一定已经有很多人帮我们想了很多办法来解决问题的。

六、重要性采样

  OK,看到这里你还没有晕过去的话,请为自己点个赞先!

  鉴于前面说的直接运用蒙特卡洛方法进行积分计算时,因为固有偏差的问题,而导致算法过程收敛过慢(N的平方根倒数的量级)所以在计算效率上是不尽人意的。那么既然是因为偏差导致的问题,我们就继续从偏差来分析看看:
σ2[Fn(X)]=1N[∫abf(x)2p(x)dx−E(Fn(X))2]=1N[∫abf(x)2p(x)dx−(∫abf(x)dx)2]\sigma^2[F_n(X)] \\[2ex] = \cfrac{1}{N} \left[ \int \limits_a^b \cfrac{{f}(x)^2}{\mathrm{p}(x)} \mathrm{d}x - E(F_n(X))^2 \right] \\[2ex] =\cfrac{1}{N} \left[ \int \limits_a^b \cfrac{{f}(x)^2}{\mathrm{p}(x)} \mathrm{d}x - \left( \int \limits_a^b {f}(x) \mathrm{d}x \right)^2 \right] σ2[Fn(X)]=N1abp(x)f(x)2dxE(Fn(X))2=N1abp(x)f(x)2dxabf(x)dx2
  这时如果我们想要标准差(方差的开方)最小,那么就需要让上式结果等于0,此时我们继续使用瞪眼法可以发现,这需要下面的等式成立:
p(x)=∣f(x)∣∫abf(x)dx(7)\mathrm{p}(x) = \cfrac{|{f}(x)|}{\int \limits_a^b {f}(x) \mathrm{d}x} \tag{7} p(x)=abf(x)dxf(x)(7)
  在很多其他的资料中,推得这个式子之后,忽略了讲解它的意义。乍看上去,貌似我们要知道我们需要使用的随机变量的概率密度,就需要先知道最终积分的结果,使得这个式子变成了无用的“鸡肋”。

  其实不然,这个式子恰恰给我们指明了一个非常明确的方向。

  它说明,如果我们要使得方差、标准差最小,那么就要找到一个随机变量序列使得它的概率密度函数与被积函数 f(x){f}(x)f(x) 在“形状”上要高度一致!这是个很重要的信息。为什么这样说呢?其实仔细观察这个式子可以发现其中的定积分其实是个常数 ∫abf(x)dx\int \limits_a^b {f}(x) \mathrm{d}xabf(x)dx ,所以整个式子表达的意思是说 :
p(x)=∣f(x)∣S=A∣f(x)∣(8)\mathrm{p}(x) = \cfrac{|{f}(x)|}{S} = A|{f}(x)| \tag{8} p(x)=Sf(x)=Af(x)(8)
  即最终当概率密度函数其实就是被积函数的一个常数倍的时候,整个方差最小,也即标准差会非常小。

  这是整个重要性采样的出发点,也就是说我们可以依据被积函数的特征,构造一个与之匹配的概率分布函数的形状,然后生成特意构造的随机序列,再返回到蒙特卡洛积分 ∫abf(x)dx≈1N∑n=1Nf(xn)p(xn)\int \limits_a^b {f}(x) \mathrm{d} x \approx \cfrac{1}{N} \sum \limits_{n=1}^{N} \cfrac{{f}(x_n)}{\mathrm{p}(x_n)}abf(x)dxN1n=1Np(xn)f(xn) 进行计算,那么只需要非常少的 xnx_nxn 就可以得到非常精确的积分结果,因为这样的序列计算后使得蒙特卡洛积分最终的方差、标准差都变得非常小,甚至为0。

  也就是说这样的随机序列,使得蒙特卡洛积分能够快速收敛!也就是说,咱们之前说的普通的蒙特卡洛积分过程误差与 1N\cfrac{1}{\sqrt{N}}N1 成正比导致我们必须付出平方倍的计算量,才能使的误差变小的规律可以被打破了,因为这个因子的后面那堆复杂的表达式在我们特意的设计下几乎 = 0,所以我们完全不用浪费过多的计算量来获取较精确的积分结果。 这个过程就被称为重要性采样!

七、重要性采样方法和过程

  那么最终如何进行上面所说的重要性采样呢?其实核心就是构造使的蒙特卡洛积分方差和标准差最小的随机数序列 xnx_nxn

  1、根据定义 ∫abp(x)dx\int \limits_a^b \mathrm{p}(x) \mathrm{d}xabp(x)dx 就是概率密度函数 p(x)p(x)p(x) 对应的累积分布函数(Cumulative Distribution Function),简称做 CDF,通常其正式定义如下:
CDF(x)=∫−∞xp(x~)dx~(9)\mathrm{CDF}(x) = \int \limits_{-\infty}^{x} p( \tilde{x} ) \mathrm{d} \tilde{x} \tag{9} CDF(x)=xp(x~)dx~(9)
  然后选择一个跟被积分的函数“相类似”的概率密度函数 PDF 来计算其 CDF;

  2、接着推导出 CDF 的反函数 CDF−1(x)\mathrm{CDF}^{-1}(x)CDF1(x)

  3、然后生成一个均匀分布的随机变量序列 un∈[0,1]u_n \in [0,1]un[0,1] ;

  4、使用 unu_nun 代入 CDF 的反函数 CDF−1(x)\mathrm{CDF}^{-1} (x)CDF1(x) 计算出随机序列 xnx_nxn ;

  5、最后将 xnx_nxn 代入蒙特卡洛积分中计算函数的积分值;

  通常在很小规模的 xnx_nxn 序列下,就可以计算出很高精度的积分值。

  举例来说,假设我们需要求一个形似 ∫0πAsin⁡(x)dx\int \limits_0^{\pi} A \sin(x) \mathrm{d}x0πAsin(x)dx 的积分,此时根据被积函数为正弦函数的特征,构造 p(x)=csin⁡(x)x∈[0,π]p(x) = c \sin(x) \quad x \in [0,\pi]p(x)=csin(x)x[0,π] ,然后我们计算它的 CDF:
∫0πcsin⁡(x)dx=c[−cos⁡(x)]0π=2c=1∵∫0πp(x)dx=1⇒c=12用x替换积分上限,得到CDF的表达式,有:CDF(x)=∫0x12sin⁡(t)dt=12[−cos⁡(t)]0x=12(1−cos⁡(x))\int \limits_{0}^{\pi} c \sin(x) \mathrm{d}x = c \Biggl[-\cos(x)\Biggr]_0^{\pi} = 2 c = 1 \\[2ex] \because \quad \int_0^{\pi} p(x) \mathrm{d}x = 1 \\[2ex] \Rightarrow c = \cfrac{1}{2} \\[2ex] 用 x 替换积分上限,得到CDF 的表达式,有: \\[2ex] CDF(x) = \int\limits_0^x \cfrac{1}{2} \sin(t)\mathrm{d}t = \cfrac{1}{2} \Biggl[ -\cos(t) \Biggr]_0^{x} = \cfrac{1}{2}(1-\cos(x)) 0πcsin(x)dx=c[cos(x)]0π=2c=10πp(x)dx=1c=21x替换积分上限,得到CDF的表达式,有:CDF(x)=0x21sin(t)dt=21[cos(t)]0x=21(1cos(x))
  有了 CDF 那么我们来计算其反函数:
y=12(1−cos⁡(x))⇒x=arccos⁡(1−2y)y = \cfrac{1}{2}(1-\cos(x)) \\[2ex] \Rightarrow \quad x = \arccos(1-2y) y=21(1cos(x))x=arccos(12y)
  接着我们生成一个均匀分布的随机数序列 unun∼[0,1]u_n \quad u_n \sim [0,1]unun[0,1] 代入上式中计算得到指定分布的随机序列 xn=arccos⁡(1−2un)x_n = \arccos(1-2u_n)xn=arccos(12un),最终用这个序列按照蒙特卡洛积分公式计算即可快速得到 ∫0πAsin⁡(x)dx\int \limits_0^{\pi} A \sin(x) \mathrm{d}x0πAsin(x)dx 的积分值。

  那么详细的计算过程和程序就先略过了,在后续的 IBL 教程中将有更详细的应用讲解和实际工程中的代码。有兴趣的同学可以自己编写程序比较一下,即先用黎曼和及库函数sin计算得到积分结果,然后与库函数cos的直接计算结果进行比较,最好能求出方差,然后再用刚才推导出的 CDF−1CDF^{-1}CDF1 函数计算的序列代入蒙特卡洛积分公式中计算积分结果,同样与cos函数直接计算的结果求差,或者求方差,看看有什么区别?

八、重要性采样的优缺点

  根据前面的叙述,重要性采样的全部目的就是为了缩小 xnx_nxn 的规模,同时还能保证一定的精度,其实就是之前标题所说的从 “蒙的挺准” 到 “蒙的更准”,而且计算量还大大变小了,这对于很多需要数值积分的计算来说是非常非常好的优化方法。另外对于高维的积分来说,重要性采样的方法依然有效!这样带来的好处就是,原本复杂度可能是 O(nα)α∈Z+,α⩾1O(n^{\alpha}) \quad \alpha \in Z^+,\alpha \geqslant 1O(nα)αZ+,α1 的问题,有可能直接变成了 O(n)O(n)O(n) 的问题,这对于我们关注的图形光照计算领域来说简直就是福音!因为我们需要处理的图形往往都是 n3n^3n3 维度的,并且在复杂光照渲染算法中需要大量的 3D 积分,所以有了蒙特卡洛积分和重要性采样方法,就使得该过程的计算量几何级数的被减少,这最终使得实时 PBR 渲染成为可能。

  当然重要性采样也有缺点,根据刚才描述的过程,大家应该能想到,第一,如果被积函数 f(x){f}(x)f(x) 过于复杂时,我们基本无法简单的模拟出一个形似的 p(x)p(x)p(x) 函数,从而整个过程有可能就前功尽弃;第二个方面就是说,通过 CDF−1CDF^{-1}CDF1 函数计算出的序列 xnx_nxn 有可能使得 f(x){f}(x)f(x) 的值过于集中于一些较大函数值得地方,从而导致最终积分的结果与真值之间产生正偏差。

  当然幸运的是这两条缺点在我们的 PBR 渲染中几乎碰不到,也就没什么太大的影响。

相关文章:

3D数学系列之——再谈特卡洛积分和重要性采样

目录一、前篇文章回顾二、积分的黎曼和形式三、积分的概率形式&#xff08;蒙特卡洛积分&#xff09;四、误差五、蒙特卡洛积分计算与收敛速度六、重要性采样七、重要性采样方法和过程八、重要性采样的优缺点一、前篇文章回顾 在前一篇文章3D数学系列之——从“蒙的挺准”到“蒙…...

Python错误 TypeError: ‘NoneType‘ object is not subscriptable解决方案汇总

目录前言一、引发错误来源二、解决方案2-1、解决方案一&#xff08;检查变量&#xff09;2-2、解决方案二&#xff08;使用 [] 而不是 None&#xff09;2-3、解决方案三&#xff08;设置默认值&#xff09;2-4、解决方案四&#xff08;使用异常处理&#xff09;2-5、解决方案五…...

VMware空间不足又无法删除快照的解决办法

如果因为快照删除半路取消或者失败&#xff0c;快照管理器就不再显示这个快照&#xff0c;但是其占用的空间还在&#xff0c;最终导致硬盘不足。 可以百度到解决方案&#xff0c;就是在快照管理器&#xff0c;先新建一个&#xff0c;再点删除&#xff0c;等待删除完成就可以将…...

类和对象(一)

类和对象&#xff08;一&#xff09; C并不是纯面向对象语言 C是面向过程和面向对象语言的&#xff01; 面向过程和面向对象初步认识&#xff1a; C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基…...

Java 不同路径

不同路径中等一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。问总共有多少条不同的路径&#xff1f…...

【SAP PO】X-DOC:SAP PO 接口配置 REST 服务对接填坑记

X-DOC&#xff1a;SAP PO 接口配置 REST 服务对接填坑记1、背景2、PO SLD配置3、PO https证书导入1、背景 &#xff08;1&#xff09;需求背景&#xff1a; SAP中BOM频繁变更&#xff0c;技术人员在对BOM进行变更后&#xff0c;希望及时通知到相关使用人员 &#xff08;2&…...

最新研究!美国爱荷华州立大学利用量子计算模拟原子核

爱荷华州立大学物理学和天文学教授James Vary&#xff08;图片来源&#xff1a;网络&#xff09;美国爱荷华州立大学物理学和天文学教授James Vary和来自爱荷华州立大学、马萨诸塞州塔夫茨大学&#xff0c;以及美国能源部加利福尼亚州劳伦斯伯克利国家实验室的研究人员&#xf…...

零入门kubernetes网络实战-22->基于tun设备实现在用户空间可以ping通外部节点(golang版本)

《零入门kubernetes网络实战》视频专栏地址 https://www.ixigua.com/7193641905282875942 本篇文章视频地址(稍后上传) 本篇文章主要是想做一个测试&#xff1a; 实现的目的是 希望在宿主机-1上&#xff0c;在用户空间里使用ping命令发起ping请求&#xff0c;产生的icmp类型的…...

web安全——Mybatis防止SQL注入 ssrf漏洞利用 DNS污染同源策略

目录 0x01 Mybatis防止SQL注入 0x02 sqlmap中报错注入判断 0x03 ssrf漏洞利用 0x04 SSRF重绑定 0x05 DNS污染...

smp_init过程解析

当你看到这样的log&#xff0c;会不会很慌张&#xff1f;竟然由CPU没有启动成功&#xff0c;除了什么故障&#xff1f;本文将结合我遇到的一个问题&#xff0c;将启动过程中bringup secondary cpu的过程分析一下。smp_init代码如下&#xff1a;602 void __init smp_init(void) …...

判断推理之逻辑判断

考点一翻译推理&#xff08;一&#xff09;题目特征题干或选项中出现多组“逻辑关联词”&#xff0c;如&#xff1a;“如果……那么……”、“只要……就……”、“只有……才……”、“所有”、“有些”、“……且……”、“ ……或……”等典型逻辑关联词。&#xff08;二&am…...

2023金三银四常见Handler面试总结,附带答案

以下的Handler的面试题都是在面试过程中总结出来比较常见的面试题&#xff0c;现在分享给大家&#xff0c;希望可以帮助你们&#xff01;1.Handler的实现原理从四个方面看Handler、Message、MessageQueue 和 Looper Handler:负责消息的发送和处理 Message:消息对象&#xff0c;…...

为什么机器人操作系统ROS1、ROS2这么难学

AI回复&#xff1a;ROS1、ROS2是机器人操作系统&#xff0c;涉及到很多复杂的概念和技术&#xff0c;需要有一定的编程和机器人知识基础才能学习。此外&#xff0c;ROS1和ROS2的架构和设计也有很大的不同&#xff0c;需要花费一定的时间和精力去学习和适应。但是&#xff0c;一…...

day01

授课老师 &#xff1a;陶国荣 联系方式 &#xff1a; taogrtedu.cn 授课阶段 &#xff1a; Web前端基础 授课内容 &#xff1a; HTML CSS JavaScript 文章目录一、讲师和课程介绍二、Web前端介绍1. 什么是网页2. 网页的组成3. 网页的优势4. 开发前的准备三、 HTML语法介绍…...

第四十章 linux-并发解决方法五(顺序锁seqlock)

第四十章 linux-并发解决方法四&#xff08;顺序锁seqlock&#xff09; 文章目录第四十章 linux-并发解决方法四&#xff08;顺序锁seqlock&#xff09;顺序锁的设计思想是&#xff0c;对某一共享数据读取时不加锁&#xff0c;写的时候加锁。为了保证读取的过程中不会因为写入名…...

【SPSS】交叉设计方差分析和协方差分析详细操作教程(附案例实战)

🤵‍♂️ 个人主页:@艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收藏 📂加关注+ 目录 方差分析概述 交叉设计方差分析...

playwright--核心概念和Selector定位

文章目录前言一、浏览器二、浏览器上下文三、页面和框架四、Selectors1、data-test-id selector2、CSS and XPath selector3、text 文本selector4、id定位selector5、Selector 组合定位五、内置Selector前言 Playwright提供了一组API可自动化操作Chromium&#xff0c;Firefox和…...

响应式操作实战案例

Project Reactor 框架 在Spring Boot 项目 Maven 中添加依赖管理。 <dependency><groupId>io.projectreactor</groupId><artifactId>reactor-core</artifactId> </dependency><dependency><groupId>io.projectreactor</g…...

NetApp AFF A900:针对任务关键型应用程序的解决方案

NetApp AFF A900&#xff1a;适用于数据中心的解决方案 AFF A 系列中的 AFF A900 高端 NVMe 闪存存储功能强大、安全可靠、具有故障恢复能力&#xff0c;提供您为任务关键型企业级应用程序提供动力并保持数据始终可用且安全所需的一切。 AFF A900&#xff1a;针对任务关键型应…...

使用Houdini输出四面体网格并输出tetgen格式

我们的目标是从houdini输出生成的四面体&#xff0c;希望是tetgen格式的。 众所周知&#xff0c;houdini是不能直接输出四面体的。 有三方案去解决&#xff1a; 输出点云ply文件&#xff0c;然后利用tetgen生成网格。输出Hounidi内置的.geo格式文件&#xff0c;然后写个脚本…...

组合预测 | MATLAB实现EMD-KPCA-LSTM、EMD-LSTM、LSTM多输入单输出回归预测对比

组合预测 | MATLAB实现EMD-KPCA-LSTM、EMD-LSTM、LSTM多输入单输出回归预测对比 目录 组合预测 | MATLAB实现EMD-KPCA-LSTM、EMD-LSTM、LSTM多输入单输出回归预测对比预测效果基本介绍模型描述程序设计参考资料预测效果 基本介绍 MATLAB实现EMD-KP...

【C语言】操作符详解总结(万字)

操作符详解1. 操作符分类2. 算术操作符3. 移位操作符3.1 整数的二进制是怎么形成的3.2 左移操作符3.3 右移操作符4. 位操作符5. 赋值操作符6. 单目操作符6.1 单目操作符介绍6.2 sizeof 和 数组7. 关系操作符8. 逻辑操作符9. 条件操作符9.1 练习19.2 练习210. 逗号表达式11. 下标…...

mac系统手册(帮助/说明)

文章目录1. mac自带的帮助文档2. Mac使用技巧&#xff08;提示&#xff09;2.1 聚焦搜索2.2 截图&#xff08;录制屏幕&#xff09;2.3 调出右键菜单2.4 快速查看2.5 翻译2.5.1 词典解释2.5.2 翻译&#xff08;字、词和句&#xff09;3. macOS使用手册3.1 在聚焦中进行计算和转…...

VLC播放器Demo(录像,截图等功能),Android播放器Demo可二次开发。

VLC播放器Demo&#xff08;录像&#xff0c;截图等功能&#xff09;&#xff0c;可二次开发。 GitHub地址:https://github.com/ILoveLin/VlcRecordPlayer GitHub地址:https://github.com/ILoveLin/VlcRecordPlayer GitHub地址:https://github.com/ILoveLin/VlcRecordPlayer …...

WeSpeaker支持C++部署链路

WeSpeaker正式更新C部署链路&#xff0c;推理引擎使用OnnxRuntime&#xff0c;支持从语音中提取Speaker Embedding信息&#xff0c;代码详见WeSpeaker/runtime[1]。 Libtorch和onnx的选择? Speaker Embedding提取任务流程简单&#xff0c;并且声纹模型&#xff08;如ResNet\E…...

window vscode编辑appsmith源码

前言 本来最开始用的idea打开wsl中的appsmith&#xff0c;卡得一批。最后没办法&#xff0c;用自己的电脑装成ubuntu server&#xff0c;然后vscode的远程开发对appsmith源码进行编辑。如果自己电脑内存16个G或者更大可能打开wsl中的估计会还好&#xff0c;我公司电脑只有8g所…...

操作系统面试题

操作系统一、简介篇1.解释一下什么是操作系统2.操作系统的主要功能3.软件访问硬件的几种方式4.操作系统的主要目的是什么5.为什么Linux系统下的应用程序不能直接在Windows下运行6.什么是用户态和内核态7.用户态和内核态如何切换8.什么是内核二、进程和线程篇1.多处理系统的优势…...

Kafka入门(七)

下面聊聊Kafka的配置参数&#xff0c;包括生产者的配置参数、Broker的配置参数、消费者的配置参数。 1、生产者配置参数 acks 该参数控制了生产者的消息发送确认机制&#xff0c;用于指定分区中必须有多少个副本成功接收到消息后生产者才会认为这条消息写入是成功的&#xff0c…...

微服务介绍

微服务 微服务架构发展 微服务这个概念最早是在2011年5月威尼斯的一个软件架构会议上讨论提出的&#xff0c;用于描述一些作为通用架构风格的设计原则&#xff1b;2012年3月在波兰举行的Degree Conference大会&#xff0c;james lewis做演讲&#xff0c;讨论了微服务一些原则…...

搭建SpringBoot多模块微服务项目脚手架(三)

搭建SpringBoot多模块微服务项目脚手架(三) 文章目录搭建SpringBoot多模块微服务项目脚手架(三)1.概述项目结构2.接口返回统一信息模板2.1.封装返回统一信息思路介绍2.2.封装json数据格式1.导入依赖2.封装code码3.封装json格式模板4.使用统一返回信息3.接口统一请求信息模板3.1…...

对vue3中reactive、toref、torefs、ref的详细理解

reactive&#xff1a;将平常的一个对象转换成响应式对象。所谓的响应式对象就是当页面点击修改此对象时&#xff0c;页面无需刷新而在页面上的其他地方有用到这个对象的地方会自动同步修改过来例如&#xff1a; <template><div class"container"><di…...

C++ Primer Plus 第6版 读书笔记(6) 第 6 章 分支语句和逻辑运算符

第 6 章 分支语句和逻辑运算符 C是在 C 语言基础上开发的一种集面向对象编程、泛型编程和过程化编程于一体的编程语言&#xff0c;是C语言的超集。本书是根据2003年的ISO/ANSI C标准编写的&#xff0c;通过大量短小精悍的程序详细而全面地阐述了 C的基本概念和技术&#xff0c;…...

Java Class 加密工具 ClassFinal

Jar包加密工具 ClassFinal介绍环境依赖使用说明下载加密命令行示例maven插件方式无密码模式机器绑定启动加密后的jar启动参数给密码不加密码参数直接启动1. 密码文件获取2. 交互输入参考资料介绍 ClassFinal 是一款 java class 文件安全加密工具&#xff0c;支持直接加密jar包…...

【蓝桥杯集训·每日一题】AcWing 3555. 二叉树

文章目录一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解三、知识风暴最近公共祖先一、题目 1、原题链接 3555. 二叉树 2、题目描述 给定一个 n 个结点&#xff08;编号 1∼n&#xff09;构成的二叉树&#xff0c;其根结点为 1 号点。 进行 m…...

【JavaScript运行原理之V8引擎】V8引擎解析JavaScript代码原理

1. 编程语言的执行 高级语言最终都需要编译为低级语言才能被硬件执行&#xff0c;越高级的语言中间的转换时间越长&#xff0c;效率越低&#xff0c;越低级的语言执行素的越快&#xff0c;但是由于缺少高级语言便捷的语法特性所以很难编写代码。 2. 大杂烩JS 它是作者在1995…...

C++11:智能指针

文章目录1. 介绍1.1 动态内存与智能指针2. 使用2.1 创建2.2 使用3. 原理3.1 RAII3.2 像指针一样使用3.3 支持智能指针对象拷贝auto_ptrRAII4. 标准库中的智能指针4.1 unique_ptr模拟实现4.2 shared_ptr引用计数模拟实现定制删除器4.3 weak_ptrshared_ptr造成的循环引用问题与sh…...

ccc-pytorch-RNN(7)

文章目录一、RNN简介二、RNN关键结构三、RNN的训练方式四、时间序列预测五、梯度弥散和梯度爆炸问题一、RNN简介 RNN&#xff08;Recurrent Neural Network&#xff09;中文循环神经网络&#xff0c;用于处理序列数据。它与传统人工神经网络和卷积神经网络的输入和输出相互独立…...

docker安装(linux)

安装需要的软件包 yum install -y yum-utils 设置stable镜像仓库&#xff08;使用阿里云镜像&#xff09; yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 更新yum软件包索引 yum makecache fast 安装DOCKER 引擎 yum -y…...

【数据库概论】10.1 事务及其作用

事务是一系列的数据库操作&#xff0c;是数据库应用程序的基本逻辑单元 10.1 事务的基本概念 1.事务 事务是用户定义的一个数据库操作序列&#xff0c;是一个具有原子性的操作&#xff0c;不可再分&#xff0c;一个事务内的操作要么全做、要么都不做。一般来说&#xff0c;一…...

通讯录(C++实现)

系统需求通讯录是一个可以记录亲人、好友信息的工具。本章主要利用C来实现一个通讯录管理系统系统中需要实现的功能如下:添加联系人:向通讯录中添加新人&#xff0c;信息包括&#xff08;姓名、性别、年龄、联系电话、家庭住址&#xff09;最多记录1000人显示联系人:显示通讯录…...

轻松掌握C++的模板与类模板,将Tamplate广泛运用于我们的编程生活

C提高编程 本阶段主要针对C泛型编程和STL技术做详细讲解&#xff0c;探讨C更深层的使用 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。 模板 1.模板的概念 模板就是建立通用的模具&#xff0c;大大提高复用性 例如&#xff1a; 2.函数模板 C另一种编程思想称…...

pandas 数据预处理+数据概览 处理技巧整理(持续更新版)

这篇文章主要是整理下使用pandas的一些技巧&#xff0c;因为经常不用它&#xff0c;这些指令忘得真的很快。前段时间在数模美赛中已经栽过跟头了&#xff0c;不希望以后遇到相关问题的时候还去网上查&#xff08;主要是太杂了&#xff09;。可能读者跟我有一样的问题&#xff0…...

mmdetectionV2.x版本 训练自己的VOC数据集

mmdetection目录下创建data文件夹&#xff0c;路劲如图所示&#xff0c;不带yololabels 修改配置文件 mmdet/datasets/voc.py 配置图片格式 mmdet/datasets/xml_style.py 如果图片是jpg则改成jpg&#xff0c;是png格式就改成png&#xff0c;这里我不需要改&#xff0c;本…...

Shell - crontab 定时 git 拉取并执行 maven 打包

目录 一.引言 二.踩坑与实践 1.原始代码 2.mvn package 未执行与解决 [导入环境变量] 3.git pull 未执行与解决 [添加绝对路径] 三.总结 一.引言 git 任务部署在通道机&#xff0c;每天6点需要定时更新 jar 包并打包上线&#xff0c;所以需要在 linux 服务器上&#xff…...

408考研计算机之计算机组成与设计——知识点及其做题经验篇目3:指令的寻址方式

上篇文章我们讲到&#xff0c;指令的基本格式&#xff0c;一条指令通常包括操作码字段和地址码字段两部分&#xff1a; 操作码字段地址码字段并且我们还讲到根据操作数地址码的数目不同&#xff0c;可将指令分为零一二三四地址指令。感兴趣的小伙伴们可以看看小编的上一篇文章…...

前端包管理工具:npm,yarn、cnpm、npx、pnpm

包管理工具npm Node Package Manager&#xff0c;也就是Node包管理器&#xff1b; 但是目前已经不仅仅是Node包管理器了&#xff0c;在前端项目中我们也在使用它来管理依赖的包&#xff1b; 比如vue、vue-router、vuex、express、koa、react、react-dom、axios、babel、webpack…...

推荐系统 FM因式分解

reference&#xff1a;知乎 FM算法解析 LR算法没有二阶交叉 如果是id类特征&#xff0c;这里的x是0/1&#xff0c;raw的特征输入就是float&#xff0c;当然&#xff0c;在我的理解里&#xff0c;一般会把raw的特征进行分桶&#xff0c;还是映射到0/1特征&#xff0c;不然这个w…...

Maven基础入门

文章目录Maven简介Maven 工作模式1.仓库2.坐标Maven的基本使用1.常用命令2.生命周期依赖管理1.依赖配置2.依赖传递3.可选依赖4.排除依赖5.依赖范围IDEA配置MavenMaven简介 Apache Maven 是一个项目管理和构建工具&#xff0c;它基于项目对象模型(POM)的概念&#xff0c;通过一…...

传输层协议 TCP UDP

目录 协议前菜 端口号 ​编辑端口号范围划分 认识知名端口号(Well-Know Port Number) netstat pidof 传输层协议 UDP协议 UDP协议端格式 UDP的特点 面向数据报 UDP的缓冲区 UDP使用注意事项 基于UDP的应用层协议 TCP协议 TCP协议概念 TCP协议段格式 标志…...

一点就分享系列(实践篇6——上篇)【迟到补发】Yolo-High_level系列算法开源项目融入V8 旨在研究和兼容使用【持续更新】

一点就分享系列&#xff08;实践篇5-补更篇&#xff09;[迟到补发]—Yolo系列算法开源项目融入V8旨在研究和兼容使用[持续更新] 题外话 去年我一直复读机式强调High-level在工业界已经饱和的情况&#xff0c;目的是呼吁更多人看准自己&#xff0c;不管是数字孪生交叉领域&#…...