从离散傅里叶变换(DFT)到快速傅里叶变换(FFT)

摘要

离散傅里叶变换(DFT)是数字信号处理领域中分析信号频域特性的重要工具,但直接计算DFT的复杂度较高,限制了其在大规模数据处理中的应用。快速傅里叶变换(FFT)的出现显著降低了计算复杂度,极大地推动了数字信号处理技术的发展。本文详细阐述了从DFT到FFT的演变过程,包括DFT的定义、计算复杂度问题,FFT的原理、算法实现以及其在实际应用中的优势,旨在帮助读者深入理解这一重要的技术变革。

在这里插入图片描述

一、引言

在数字信号处理的众多任务中,如信号滤波、频谱分析、通信系统中的调制解调等,频域分析是关键环节。离散傅里叶变换(DFT)为我们提供了将离散时间信号从时域转换到频域的方法,使得我们能够观察信号在不同频率上的分布情况。然而,DFT的直接计算涉及大量的乘法和加法运算,计算复杂度较高,尤其是当信号长度较长时,计算时间会显著增加,这在实际应用中成为了一个瓶颈。为了解决这一问题,快速傅里叶变换(FFT)应运而生。FFT通过巧妙的算法设计,大大减少了计算量,提高了计算效率,使得频域分析能够在更短的时间内完成,从而推动了数字信号处理技术在各个领域的广泛应用。

二、离散傅里叶变换(DFT)

2.1 DFT的定义

对于长度为 N N N 的离散时间序列 x [ n ] x[n] x[n] n = 0 , 1 , ⋯ , N − 1 n = 0,1,\cdots,N - 1 n=0,1,,N1,其离散傅里叶变换(DFT)定义为:
X [ k ] = ∑ n = 0 N − 1 x [ n ] e − j 2 π N k n , k = 0 , 1 , ⋯ , N − 1 X[k]=\sum_{n = 0}^{N - 1}x[n]e^{-j\frac{2\pi}{N}kn}, k = 0,1,\cdots,N - 1 X[k]=n=0N1x[n]ejN2πkn,k=0,1,,N1
其中, X [ k ] X[k] X[k] 是长度为 N N N 的离散频域序列, k k k 是离散的频率序号, e − j 2 π N e^{-j\frac{2\pi}{N}} ejN2π 通常记为 W N W_N WN,称为旋转因子。

DFT的逆变换(IDFT)定义为:
x [ n ] = 1 N ∑ k = 0 N − 1 X [ k ] e j 2 π N k n , n = 0 , 1 , ⋯ , N − 1 x[n]=\frac{1}{N}\sum_{k = 0}^{N - 1}X[k]e^{j\frac{2\pi}{N}kn}, n = 0,1,\cdots,N - 1 x[n]=N1k=0N1X[k]ejN2πkn,n=0,1,,N1

2.2 DFT的物理意义

DFT将时域的离散序列 x [ n ] x[n] x[n] 分解为 N N N 个不同频率的复指数序列的线性组合,每个复指数序列的频率为 ω k = 2 π N k \omega_k=\frac{2\pi}{N}k ωk=N2πk k = 0 , 1 , ⋯ , N − 1 k = 0,1,\cdots,N - 1 k=0,1,,N1 X [ k ] X[k] X[k] 表示序列 x [ n ] x[n] x[n] 在频率 ω k \omega_k ωk 处的频谱分量,其幅度 ∣ X [ k ] ∣ |X[k]| X[k] 反映了该频率分量的强度,相位 ∠ X [ k ] \angle X[k] X[k] 反映了该频率分量的相位信息。通过DFT,我们可以在频域中分析信号的频率成分,了解信号的特性。

2.3 DFT的计算复杂度

直接计算DFT时,对于每个 k k k 值,需要进行 N N N 次复数乘法和 N − 1 N - 1 N1 次复数加法。由于 k k k N N N 个取值,所以总的复数乘法次数约为 N 2 N^2 N2 次,复数加法次数约为 N ( N − 1 ) N(N - 1) N(N1) 次。当 N N N 较大时,计算量会急剧增加。例如,当 N = 1024 N = 1024 N=1024 时,直接计算DFT需要进行约 102 4 2 = 1048576 1024^2 = 1048576 10242=1048576 次复数乘法,这对于实时性要求较高的应用来说是难以承受的。因此,DFT计算复杂度高的问题限制了其在实际中的广泛应用。

三、快速傅里叶变换(FFT)的原理

3.1 分治思想的引入

为了降低DFT的计算复杂度,人们提出了快速傅里叶变换(FFT)算法。FFT的核心思想是利用分治策略,将一个 N N N 点的DFT分解为多个较短长度的DFT来计算。以基 - 2时间抽取FFT算法为例(假设 N = 2 M N = 2^M N=2M M M M 为正整数),把 N N N 点序列 x [ n ] x[n] x[n] n n n 的奇偶性分为两个 N / 2 N/2 N/2 点的子序列:

  • 偶数序号子序列: x 1 [ r ] = x [ 2 r ] x_1[r]=x[2r] x1[r]=x[2r] r = 0 , 1 , ⋯ , N / 2 − 1 r = 0,1,\cdots,N/2 - 1 r=0,1,,N/21
  • 奇数序号子序列: x 2 [ r ] = x [ 2 r + 1 ] x_2[r]=x[2r + 1] x2[r]=x[2r+1] r = 0 , 1 , ⋯ , N / 2 − 1 r = 0,1,\cdots,N/2 - 1 r=0,1,,N/21

N N N 点DFT X [ k ] X[k] X[k] 可以表示为:
X [ k ] = ∑ n = 0 N − 1 x [ n ] W N k n = ∑ r = 0 N / 2 − 1 x [ 2 r ] W N k ( 2 r ) + ∑ r = 0 N / 2 − 1 x [ 2 r + 1 ] W N k ( 2 r + 1 ) = ∑ r = 0 N / 2 − 1 x 1 [ r ] W N / 2 k r + W N k ∑ r = 0 N / 2 − 1 x 2 [ r ] W N / 2 k r = X 1 [ k ] + W N k X 2 [ k ] , k = 0 , 1 , ⋯ , N − 1 \begin{align*} X[k]&=\sum_{n = 0}^{N - 1}x[n]W_N^{kn}\\ &=\sum_{r = 0}^{N/2 - 1}x[2r]W_N^{k(2r)}+\sum_{r = 0}^{N/2 - 1}x[2r + 1]W_N^{k(2r+1)}\\ &=\sum_{r = 0}^{N/2 - 1}x_1[r]W_{N/2}^{kr}+W_N^k\sum_{r = 0}^{N/2 - 1}x_2[r]W_{N/2}^{kr}\\ &=X_1[k]+W_N^kX_2[k], k = 0,1,\cdots,N - 1 \end{align*} X[k]=n=0N1x[n]WNkn=r=0N/21x[2r]WNk(2r)+r=0N/21x[2r+1]WNk(2r+1)=r=0N/21x1[r]WN/2kr+WNkr=0N/21x2[r]WN/2kr=X1[k]+WNkX2[k],k=0,1,,N1
其中 W N = e − j 2 π N W_N = e^{-j\frac{2\pi}{N}} WN=ejN2π W N / 2 = e − j 2 π N / 2 = e − j 4 π N W_{N/2}=e^{-j\frac{2\pi}{N/2}}=e^{-j\frac{4\pi}{N}} WN/2=ejN/22π=ejN4π X 1 [ k ] X_1[k] X1[k] X 2 [ k ] X_2[k] X2[k] 分别是 x 1 [ r ] x_1[r] x1[r] x 2 [ r ] x_2[r] x2[r] N / 2 N/2 N/2 点DFT。

由于 X 1 [ k ] X_1[k] X1[k] X 2 [ k ] X_2[k] X2[k] 具有周期性,即 X 1 [ k + N / 2 ] = X 1 [ k ] X_1[k + N/2]=X_1[k] X1[k+N/2]=X1[k] X 2 [ k + N / 2 ] = X 2 [ k ] X_2[k + N/2]=X_2[k] X2[k+N/2]=X2[k] 所以 X [ k ] X[k] X[k] 可以进一步表示为:
{ X [ k ] = X 1 [ k ] + W N k X 2 [ k ] , k = 0 , 1 , ⋯ , N / 2 − 1 X [ k + N / 2 ] = X 1 [ k ] − W N k X 2 [ k ] , k = 0 , 1 , ⋯ , N / 2 − 1 \begin{cases} X[k]=X_1[k]+W_N^kX_2[k],& k = 0,1,\cdots,N/2 - 1\\ X[k + N/2]=X_1[k]-W_N^kX_2[k],& k = 0,1,\cdots,N/2 - 1 \end{cases} {X[k]=X1[k]+WNkX2[k],X[k+N/2]=X1[k]WNkX2[k],k=0,1,,N/21k=0,1,,N/21

这样,一个 N N N 点的DFT就可以通过两个 N / 2 N/2 N/2 点的DFT来计算。继续对 N / 2 N/2 N/2 点的DFT进行分解,直到分解为2点的DFT,最终可以将计算复杂度从 O ( N 2 ) O(N^2) O(N2) 降低到 O ( N log ⁡ 2 N ) O(N\log_2N) O(Nlog2N)

3.2 旋转因子的特性

旋转因子 W N = e − j 2 π N W_N = e^{-j\frac{2\pi}{N}} WN=ejN2π 具有以下重要特性,这些特性在FFT算法中起到了关键作用:

  • 周期性 W N k + N = W N k W_N^{k + N}=W_N^k WNk+N=WNk,这是因为 e − j 2 π N ( k + N ) = e − j 2 π N k e − j 2 π = e − j 2 π N k e^{-j\frac{2\pi}{N}(k + N)}=e^{-j\frac{2\pi}{N}k}e^{-j2\pi}=e^{-j\frac{2\pi}{N}k} ejN2π(k+N)=ejN2πkej2π=ejN2πk利用周期性,我们可以避免重复计算旋转因子的值。
  • 对称性 W N k + N / 2 = − W N k W_N^{k+N/2}=-W_N^k WNk+N/2=WNk,因为 W N k + N / 2 = e − j 2 π N ( k + N / 2 ) = e − j 2 π N k e − j π = − e − j 2 π N k = − W N k W_N^{k + N/2}=e^{-j\frac{2\pi}{N}(k + N/2)}=e^{-j\frac{2\pi}{N}k}e^{-j\pi}=-e^{-j\frac{2\pi}{N}k}=-W_N^k WNk+N/2=ejN2π(k+N/2)=ejN2πke=ejN2πk=WNk对称性可以减少旋转因子的计算量,进一步提高算法效率。

3.3 蝶形运算

蝶形运算是FFT算法中的基本运算单元。对于基 - 2 FFT算法,一个蝶形运算涉及两个输入数据 a a a b b b,以及一个旋转因子 W N k W_N^k WNk,其输出为:
{ A = a + W N k b B = a − W N k b \begin{cases} A=a + W_N^kb\\ B=a - W_N^kb \end{cases} {A=a+WNkbB=aWNkb

在基 - 2时间抽取FFT算法中,每一级都由多个蝶形运算组成。通过不断地进行蝶形运算,最终可以得到 N N N 点的FFT结果。蝶形运算的优点是只需要一次复数乘法和两次复数加法,大大减少了计算量。

四、FFT算法的实现

4.1 基 - 2 时间抽取 FFT 算法的实现步骤

4.1.1 输入序列的重排

在基 - 2 时间抽取 FFT 算法中,输入序列 x [ n ] x[n] x[n] 需要按照比特倒序的方式进行重排。假设序列长度 N = 2 M N = 2^M N=2M,对于序号 n n n,将其表示为 M M M 位二进制数,然后将这 M M M 位二进制数按位反转得到新的序号 n ′ n' n,将 x [ n ] x[n] x[n] 放置到 x [ n ′ ] x[n'] x[n] 的位置。例如,当 N = 8 N = 8 N=8 M = 3 M = 3 M=3)时, n = 3 n = 3 n=3 的二进制表示为 011 011 011,比特倒序后为 110 110 110,即 6 6 6,那么 x [ 3 ] x[3] x[3] 要与 x [ 6 ] x[6] x[6] 交换位置。这样做的目的是为后续的蝶形运算提供方便,使得运算可以按照规则的顺序进行。

4.1.2 多级蝶形运算

将重排后的序列进行 M M M 级蝶形运算,每一级包含 N / 2 N/2 N/2 个蝶形单元。以第 m m m 级( m = 1 , 2 , ⋯ , M m = 1,2,\cdots,M m=1,2,,M)为例,同一级中每个蝶形单元的旋转因子为 W N r 2 M − m W_N^{r2^{M - m}} WNr2Mm其中 r = 0 , 1 , ⋯ , 2 m − 1 − 1 r = 0,1,\cdots,2^{m - 1}-1 r=0,1,,2m11。每一级的蝶形运算都根据前面提到的蝶形运算公式 A = a + W N k b A=a + W_N^kb A=a+WNkb B = a − W N k b B=a - W_N^kb B=aWNkb 进行计算,不断更新序列的值。

下面是一个用 Python 实现基 - 2 时间抽取 FFT 算法的示例代码:

import numpy as npdef bit_reverse(x):N = len(x)M = int(np.log2(N))x_reversed = np.zeros(N, dtype=complex)for n in range(N):binary_n = bin(n)[2:].zfill(M)reversed_n = int(binary_n[::-1], 2)x_reversed[n] = x[reversed_n]return x_reverseddef fft(x):N = len(x)if N <= 1:return xx = bit_reverse(x)M = int(np.log2(N))for m in range(1, M + 1):group_size = 2**mhalf_group_size = group_size // 2for k in range(0, N, group_size):for r in range(half_group_size):W = np.exp(-2j * np.pi * r / group_size)a = x[k + r]b = x[k + r + half_group_size]x[k + r] = a + W * bx[k + r + half_group_size] = a - W * breturn x

4.2 其他 FFT 算法变体

除了基 - 2 时间抽取 FFT 算法,还有基 - 2 频率抽取 FFT 算法、基 - 4 FFT 算法以及分裂基 FFT 算法等。

4.2.1 基 - 2 频率抽取 FFT 算法

基 - 2 频率抽取 FFT 算法与基 - 2 时间抽取 FFT 算法类似,但它是在频域进行分解。它将 N N N 点 DFT 分解为两个 N / 2 N/2 N/2 点 DFT 的组合,不过分解的方式和蝶形运算的结构与时间抽取算法有所不同。频率抽取算法在输入序列不需要进行比特倒序重排,而是在输出序列进行比特倒序,这在某些应用场景中可能更具优势。

4.2.2 基 - 4 FFT 算法

当序列长度 N N N 是 4 的幂次方(即 N = 4 M N = 4^M N=4M)时,可以使用基 - 4 FFT 算法。基 - 4 算法将 N N N 点 DFT 分解为四个 N / 4 N/4 N/4 点 DFT,相比于基 - 2 算法,它能进一步减少乘法运算的次数。因为基 - 4 蝶形运算可以用更少的乘法实现,从而提高计算效率。

4.2.3 分裂基 FFT 算法

分裂基 FFT 算法结合了基 - 2 和基 - 4 算法的优点,它在分解过程中根据序列长度灵活地采用基 - 2 和基 - 4 的分解方式。分裂基算法在计算效率上通常优于单纯的基 - 2 或基 - 4 算法,尤其是对于较长的序列,能显著减少乘法和加法的运算次数。

五、FFT 相对于 DFT 的优势

5.1 计算复杂度的显著降低

如前文所述,直接计算 DFT 的复杂度为 O ( N 2 ) O(N^2) O(N2),而 FFT 算法(如基 - 2 时间抽取 FFT)的复杂度为 O ( N log ⁡ 2 N ) O(N\log_2N) O(Nlog2N)。当 N N N 较大时, N log ⁡ 2 N N\log_2N Nlog2N 远小于 N 2 N^2 N2。例如,当 N = 1024 N = 1024 N=1024 时,DFT 需要约 102 4 2 = 1048576 1024^2 = 1048576 10242=1048576 次复数乘法,而基 - 2 FFT 只需要约 1024 2 log ⁡ 2 1024 = 512 × 10 = 5120 \frac{1024}{2}\log_2{1024}= 512\times10 = 5120 21024log21024=512×10=5120 次复数乘法,计算效率得到了极大的提高。这使得 FFT 能够处理更长的信号序列,并且在更短的时间内完成频域分析任务。

5.2 实时处理能力的提升

在许多实际应用中,如音频和视频处理、雷达信号处理等,对信号处理的实时性要求很高。由于 FFT 算法大大减少了计算量,使得系统能够在更短的时间内完成频域分析,从而满足实时处理的需求。例如,在音频实时特效处理中,通过 FFT 可以快速分析音频信号的频谱,然后根据频谱信息进行滤波、均衡等处理,最后通过逆 FFT 将处理后的频谱转换回时域,实现实时的音频效果调整。

5.3 硬件实现的可行性增强

较低的计算复杂度使得 FFT 更容易在硬件上实现。相比于 DFT 所需的大量乘法器和加法器,FFT 算法的规则结构和较少的运算次数使得它可以用更简单的硬件电路来实现。例如,在现场可编程门阵列(FPGA)和专用集成电路(ASIC)中,FFT 模块可以高效地实现,从而为各种嵌入式系统和实时信号处理设备提供强大的频域处理能力。

六、FFT 在实际应用中的广泛应用

6.1 音频处理

在音频处理领域,FFT 被广泛应用于音频的频谱分析、滤波、压缩等方面。通过 FFT 可以将音频信号从时域转换到频域,分析音频信号的频率成分,例如检测音频中的高音、低音成分,以及识别音频中的特定频率特征,如人声的基频和各次谐波。在音频滤波中,可以根据频谱分析的结果设计滤波器,去除不需要的频率成分,如噪声。在音频压缩方面,FFT 可以帮助确定音频信号的主要频率分量,然后对这些分量进行量化和编码,从而实现音频数据的压缩。

6.2 图像处理

在图像处理中,FFT 用于图像的频域滤波、特征提取等操作。图像的低频成分对应着图像的整体轮廓和缓慢变化的部分,高频成分对应着图像的细节和边缘信息。通过对图像进行二维 FFT 变换,可以将图像从空间域转换到频域,然后在频域中对图像进行滤波处理。例如,使用低通滤波器可以平滑图像,去除图像中的高频噪声;使用高通滤波器可以增强图像的边缘信息,使图像更加清晰。此外,FFT 还可以用于图像的特征提取,通过分析图像的频谱特征来识别图像中的物体或模式。

6.3 通信系统

在通信系统中,FFT 是正交频分复用(OFDM)技术的核心算法。OFDM 是一种高效的多载波调制技术,它将高速数据流分成多个低速子数据流,每个子数据流在不同的子载波上进行传输。FFT 和逆 FFT 用于实现 OFDM 信号在频域和时域之间的转换。在发射端,通过逆 FFT 将频域的子载波数据转换为时域的 OFDM 符号;在接收端,通过 FFT 将接收到的时域 OFDM 符号转换回频域,然后进行解调。FFT 的高效计算使得 OFDM 技术能够在有限的频谱资源下实现高速、可靠的通信。

6.4 雷达信号处理

在雷达信号处理中,FFT 用于对雷达回波信号进行频谱分析,以确定目标的速度、距离等信息。雷达发射的信号遇到目标后会产生回波,回波信号包含了目标的各种信息。通过对回波信号进行 FFT 变换,可以得到其频谱特性,根据多普勒频移原理计算目标的速度;根据回波信号的延迟时间和频率信息,可以估计目标的距离。FFT 的快速计算能力使得雷达系统能够实时地对目标进行检测和跟踪。

七、结论

从离散傅里叶变换(DFT)到快速傅里叶变换(FFT)的发展是数字信号处理领域的一个重要里程碑。DFT 为我们提供了一种将离散时间信号从时域转换到频域的基本方法,但由于其计算复杂度高,限制了其在大规模数据处理和实时应用中的使用。FFT 算法通过引入分治思想,利用旋转因子的特性和蝶形运算,成功地将计算复杂度从 O ( N 2 ) O(N^2) O(N2) 降低到 O ( N log ⁡ 2 N ) O(N\log_2N) O(Nlog2N),大大提高了计算效率。

FFT 不仅在计算复杂度上具有显著优势,还提升了信号处理的实时性和硬件实现的可行性。它在音频处理、图像处理、通信系统、雷达信号处理等众多实际应用领域发挥着至关重要的作用,推动了这些领域的技术发展。随着科技的不断进步,FFT 算法也在不断改进和优化,出现了多种变体算法,以适应不同的应用场景和需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/69267.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【3分钟极速部署】在本地快速部署deepseek

第一步&#xff0c;找到网站&#xff0c;下载&#xff1a; 首先找到Ollama &#xff0c; 根据自己的电脑下载对应的版本 。 我个人用的是Windows 我就先尝试用Windows版本了 &#xff0c;文件不是很大&#xff0c;下载也比较的快 第二部就是安装了 &#xff1a; 安装完成后提示…

Zookeeper入门部署(单点与集群)

本篇文章基于docker方式部署zookeeper集群&#xff0c;请先安装docker 目录 1. docker初期准备 2.启动zookeeper 2.1 单点部署 2.2 集群部署 3. Linux脚本实现快速切换启动关闭 1. docker初期准备 拉取zookeeper镜像 docker pull zookeeper:3.5.6 如果拉取时间过长&#xf…

QMK启用摇杆和鼠标按键功能

虽然选择了触摸屏&#xff0c;我仍选择为机械键盘嵌入摇杆模块&#xff0c;这本质上是对"操作连续性"的执着。   值得深思的是&#xff0c;本次开发过程中借助DeepSeek的代码生成与逻辑推理&#xff0c;其展现的能力已然颠覆传统编程范式&#xff0c;需求描述可自动…

Linux里的容器被OOM killed的两种情况

生产上遇到过几次容器实例被OOM的现象&#xff0c;总结一下LInux OOM的两种触发条件。我的虚拟机是ubuntu 24.0.4版本&#xff0c;分配4G内存&#xff0c;在我的虚拟机上复现这两种case。 一 宿主机物理内存不够 当linux上所有应用程序的内存需求加起来超出了物理内存&#x…

Windows本地部署DeepSeek-R1大模型并使用web界面远程交互

文章目录 前言1. 安装Ollama2. 安装DeepSeek-r1模型3. 安装图形化界面3.1 Windows系统安装Docker3.2 Docker部署Open WebUI3.3 添加Deepseek模型 4. 安装内网穿透工具5. 配置固定公网地址 前言 最近爆火的国产AI大模型Deepseek详细大家都不陌生&#xff0c;不过除了在手机上安…

低代码开发与传统开发:未来的技术路线选择

在科技飞速发展的当下&#xff0c;软件开发技术日新月异&#xff0c;低代码开发与传统开发作为两种重要的开发模式&#xff0c;正站在未来技术路线选择的十字路口&#xff0c;引发了众多企业和开发者的关注。它们各自有着独特的优势和适用场景&#xff0c;究竟该如何抉择&#…

二、0-1搭建springboot+vue3前后端分离-登录页面

项目仓库地址&#xff1a;zgw-admin: 从0-1搭建一个springbootvue3的项目&#xff0c;这是源码 本次主要是为了&#xff1a; a.写登录页面 b.element plus组件是否能正常使用 c.页面调用ts是否正常&#xff0c;无参和有参的函数 首页的图片&#xff1a; 页面效果 1、引入…

Spring Task之Cron表达式

&#x1f31f; Spring Task高能预警&#xff1a;你以为的Cron表达式可能都是错的&#xff01;【附实战避坑指南】 开篇暴击&#xff1a;为什么你的定时任务总在凌晨3点翻车&#xff1f; “明明设置了0 0 2 * * ?&#xff0c;为什么任务每天凌晨3点执行&#xff1f;” —— 来…

web-JSON Web Token-CTFHub

前言 在众多的CTF平台当中&#xff0c;作者认为CTFHub对于初学者来说&#xff0c;是入门平台的不二之选。CTFHub通过自己独特的技能树模块&#xff0c;可以帮助初学者来快速入门。具体请看官方介绍&#xff1a;CTFHub。 作者更新了CTFHub系列&#xff0c;希望小伙伴们多多支持…

【FPGA】 MIPS 12条整数指令【2】

目录 实现slt 仿真 代码 完整代码 ID.v DataMem.v define.v EX.v IF.v InstMem.v MEM.v MIPS.v RegFile.v Soc.v soc_tb.v 实现slt 仿真 ori r1,r0,1100h ori r2,r0,0020h ori r3,r0,ff00h ori r4,r0,ffffh addi r5,r0,ffff slt r6,r5,r4 slt r6,r4,r…

C基础寒假练习(6)

一、终端输入行数&#xff0c;打印倒金字塔 #include <stdio.h> int main() {int rows;printf("请输入倒金字塔的行数: ");scanf("%d", &rows);for (int i rows; i > 0; i--) {// 打印空格for (int j 0; j < rows - i; j) {printf(&qu…

【C# 】图像资源的使用

在C#中&#xff0c;图像资源的使用方式方法主要依赖于你所使用的框架和库。以下是几种常见的使用图像资源的方法&#xff1a; Windows Forms 直接加载图像&#xff1a; 使用System.Drawing.Image.FromFile()方法可以直接从文件系统加载图像。 Image image Image.FromFile(&qu…

OpenGL学习笔记(六):Transformations 变换(变换矩阵、坐标系统、GLM库应用)

文章目录 向量变换使用GLM变换&#xff08;缩放、旋转、位移&#xff09;将变换矩阵传递给着色器坐标系统与MVP矩阵三维变换绘制3D立方体 & 深度测试&#xff08;Z-buffer&#xff09;练习1——更多立方体 现在我们已经知道了如何创建一个物体、着色、加入纹理。但它们都还…

OSPF基础(1):工作过程、状态机、更新

OSPF基础 1、技术背景&#xff08;与RIP密不可分&#xff0c;因为RIP中存在的问题&#xff09; RIP中存在最大跳数为15的限制&#xff0c;不能适应大规模组网周期性发送全部路由信息&#xff0c;占用大量的带宽资源以路由收敛速度慢以跳数作为度量值存在路由环路可能性每隔30秒…

python爬虫--简单登录

1&#xff0c;使用flask框架搭建一个简易网站 后端代码app.py from flask import Flask, render_template, request, redirect, url_for, sessionapp Flask(__name__) app.secret_key 123456789 # 用于加密会话数据# 模拟用户数据库 users {user1: {password: password1}…

如何在React中使用Redux进行状态管理?

在现代前端开发中&#xff0c;React已成为构建用户界面的流行选择。然而&#xff0c;随着应用规模的不断增长&#xff0c;管理组件之间的状态变得愈加复杂。为了解决这一问题&#xff0c;Redux 作为一种状态管理工具应运而生。本文将详细介绍如何在React中集成和使用Redux来进行…

HTML中的图片标签详解及路径使用【学术投稿-第五届环境资源与能源工程国际学术会议(ICEREE 2025)】

官网&#xff1a;www.iceree.org 会议时间&#xff1a;2025年2月21-23日 会议地点&#xff1a;中国-昆明 简介 第五届环境资源与能源工程国际学术会议&#xff08;ICEREE 2025&#xff09;将于2025年2月21日至23日在中国昆明隆重举行。主要围绕“能源工程和能源技术”、“环…

react的antd表格自定义图标

将原版的加号换成箭头 自定义图标 安装图标包&#xff1a; npm install --save ant-design/icons 引入&#xff1a; import { RightOutlined, DownOutlined } from ant-design/icons; 参数是一个函数 <Table columns{columns} dataSource{data} indentSize{20}expandIc…

【回溯+剪枝】单词搜索,你能用递归解决吗?

文章目录 79. 单词搜索解题思路&#xff1a;回溯&#xff08;深搜&#xff09; 剪枝 79. 单词搜索 79. 单词搜索 ​ 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 …

Redis企业开发实战(二)——点评项目之商户缓存查询

目录 一、缓存介绍 二、缓存更新策略 三、如何保证redis与数据库一致性 1.解决方案概述 2.双写策略 3.双删策略 3.1延迟双删的目的 4.数据重要程度划分 四、缓存穿透 (一)缓存穿透解决方案 (二)缓存穿透示意图 五、缓存雪崩 (一)缓存雪崩解决方案 (二)缓存雪崩…