什么是幂等运算?

什么是幂等运算?


#1楼

无论您调用该操作多少次,结果都是一样的。


#2楼

在计算中,幂等运算是指如果使用相同的输入参数多次调用幂等运算,则不会产生任何其他影响。 例如,从集合中删除项目可以视为对该集合的幂等操作。

在数学中,幂等运算是f(f(x))= f(x)的情况 。 例如, abs()函数是幂等的,因为对于所有x abs(abs(x)) = abs(x)

通过考虑数学定义中的x表示对象的状态,并且f是可以使该对象变异的运算,可以调和这些稍有不同的定义。 例如,考虑Python set及其discard方法。 discard方法从集合中删除一个元素,如果该元素不存在,则不执行任何操作。 所以:

my_set.discard(x)

与执行两次相同的操作具有完全相同的效果:

my_set.discard(x)
my_set.discard(x)

幂等操作通常用于网络协议的设计中,在该协议中,执行一项操作的请求至少会发生一次,但也可能会发生多次。 如果该操作是幂等的,则两次执行此操作不会有任何危害。

有关更多信息,请参见有关幂等性的Wikipedia文章。


上面的答案以前有一些不正确和误导性的例子。以下注释是在2014年4月之前写的,是较旧的版本。


#3楼

只要您传入相同的参数,即使多次调用幂等运算,结果也会在相同的状态下产生。


#4楼

任何第n个结果都将导致输出与第一个结果的值匹配的任何操作。 例如,-1的绝对值为1。-1的绝对值的绝对值为1。-1的绝对值的绝对值的绝对值为1。依此类推。

另请参阅:什么时候使用递归真的很愚蠢?


#5楼

一个集合上的幂等运算在被应用一次或多次后,其成员保持不变。

它可以是绝对值(x)之类的一元运算,其中x属于一组正整数。 这里的absolute(absolute(x))= x。

它可以是二进制运算,就像集合与自身的将始终返回同一集合一样。

干杯


#6楼

幂等运算可以重复任意次,其结果将与仅进行一次相同。 在算术中,将零加到数字上是幂等的。

在“ RESTful” Web服务的上下文中讨论了幂等性。 REST试图最大程度地利用HTTP来使程序访问Web内容,并且通常与基于SOAP的Web服务形成对比,后者只是在HTTP请求和响应中建立远程过程调用样式服务。

REST将Web应用程序组织为“资源”(例如Twitter用户或Flickr图像),然后使用POST,PUT,GET和DELETE的HTTP动词来创建,更新,读取和删除这些资源。

幂等在REST中扮演重要角色。 如果您获取REST资源的表示形式(例如,从Flickr获取jpeg图像),并且操作失败,则可以一次又一次地重复GET,直到操作成功。 对于Web服务,获取图像的次数无关紧要。 同样,如果您使用RESTful Web服务来更新您的Twitter帐户信息,则可以多次输入新信息,以便从Web服务获得确认。 将其放置一千次与放置一次相同。 同样,将REST资源删除一千次与删除一次相同。 因此,幂等性使构建可抵抗通信错误的Web服务变得容易得多。

进一步阅读:Richardson和Ruby 撰写的 RESTful Web服务 (关于幂等性在第103-104页上进行了讨论),以及Roy Fielding的REST博士学位论文 。 Fielding是HTTP 1.1 RFC-2616的作者之一,在第9.1.2节中讨论了幂等性。


#7楼

幂等运算:如果多次执行,则没有副作用。
示例 :从数据资源中检索值并进行打印的操作

非等幂运算:如果多次执行,会造成一定危害。 (因为它们更改了某些值或状态)
示例:从银行帐户提取的操作


#8楼

只是想抛出一个证明幂等的真实用例。 在JavaScript中,假设您正在定义一堆模型类(如在MVC模型中)。 通常实现的方式在功能上等效于以下示例(基本示例):

function model(name) {
  function Model() {
    this.name = name;
  }

  return Model;
}

然后,您可以像这样定义新的类:

var User = model('user');
var Article = model('article');

但是,如果您尝试通过model('user')从代码的其他位置获取User类,它将失败:

var User = model('user');
// ... then somewhere else in the code (in a different scope)
var User = model('user');

这两个User构造函数将有所不同。 那是,

model('user') !== model('user');

为了使其幂等 ,您只需添加某种缓存机制,如下所示:

var collection = {};

function model(name) {
  if (collection[name])
    return collection[name];

  function Model() {
    this.name = name;
  }

  collection[name] = Model;
  return Model;
}

通过添加缓存,每当您对model('user')进行model('user') ,它将成为同一对象,因此是幂等的。 所以:

model('user') === model('user');

#9楼

我的5c:在集成和网络中,幂等性非常重要。 现实生活中的几个例子:想象一下,我们将数据传递到目标系统。 通过一系列消息传递的数据。 1.如果序列在通道中混合会发生什么? (因为网络软件包总是这样做:))。 如果目标系统是幂等的,结果将不会有所不同。 如果目标系统依赖于顺序中的正确顺序,则我们必须在目标站点上实现重新排序器,这将恢复正确的顺序。 2.如果消息重复,该怎么办? 如果目标系统的通道未及时确认,则源系统(或通道本身)通常会发送该消息的另一个副本。 结果,我们可以在目标系统侧获得重复的消息。 如果目标系统是幂等的,它会照顾好它,结果将不会改变。 如果目标系统不是幂等的,则必须在通道的目标系统侧实现重复数据删除器。


#10楼

幂等操作是可以多次应用的操作,操作或请求,而不会改变结果(即系统状态),超出了最初的应用程序。

示例(Web应用程序上下文):

决定因素:发出多个相同的请求与发出单个请求具有相同的效果。 电子邮件消息系统中的一条消息已打开,并在数据库中标记为“已打开”。 一个人可以多次打开该消息,但是重复执行此操作只会导致该消息处于“打开”状态。 这是一个幂等操作。 第一次使用与资源不匹配的信息(系统状态)PUT对资源进行更新时,系统状态将随着资源更新而改变。 如果一个PUT重复对资源进行相同的更新,则更新中的信息将与每个PUT上已经存在于系统中的信息相匹配,并且不会更改系统状态。 具有相同信息的重复PUT是幂等的:第一个PUT可能会更改系统状态,而后续的PUT则不会。

非强制性:如果某个操作总是引起状态变化,例如一次又一次地向用户发布同一条消息,导致每次都发送新消息并将其存储在数据库中,那么我们就说该操作是非强制性的。

NULLIPOTENT:如果操作没有副作用,例如仅在网页上显示信息而不对数据库进行任何更改(换句话说,您仅在读取数据库),则说该操作为NULLIPOTENT。 所有GET均应无效。

在谈论系统状态时,我们显然忽略了希望的无害和不可避免的影响,例如日志记录和诊断。


#11楼

相当详细和技术性的答案。 只需添加一个简单的定义。

幂等=可重新运行

例如,如果多次执行,则不能保证Create操作本身不会出错。 但是,如果存在操作CreateOrUpdate那么它将声明可重新运行性(Idempotency)。


#12楼

简而言之 ,幂等运算意味着无论您操作幂等运算多少次,该操作都不会导致不同的结果。

例如,根据HTTP规范的定义, GET, HEAD, PUT, and DELETE是幂等操作; 但是POST and PATCH不是。 这就是为什么有时POSTPUT代替的原因。


#13楼

重试安全。

通常是了解其在计算机科学中含义的最简单方法。


#14楼

理解幂等操作的一个很好的例子可能是用遥控钥匙锁定汽车。

log(Car.state) // unlocked

Remote.lock();
log(Car.state) // locked

Remote.lock();
Remote.lock();
Remote.lock();
log(Car.state) // locked

lock是幂等操作。 即使每次lock时都有一些副作用,例如闪烁,汽车仍处于相同的锁定状态。


#15楼

幂等是指一次执行一项操作或多次执行一项操作具有相同的效果。

例子:

  • 乘以零。 无论您执行多少次,结果仍然为零。
  • 设置一个布尔标志。 无论您执行多少次,该标志都会保持设置状态。
  • 从具有给定ID的数据库中删除一行。 如果再次尝试,该行仍然不存在。

对于纯函数 (没有副作用的函数),幂等性意味着f(x)= f(f(x))= f(f(f(x()))= f(f(f(f(x))) )= ......对于x的所有值

对于具有副作用的功能 ,幂等性还意味着在首次应用后不会引起其他副作用。 如果愿意,可以将世界状况视为该函数的附加“隐藏”参数。

请注意,在一个同时进行并行操作的世界中,您可能会发现原来认为是幂等的操作不再如此(例如,在上面的示例中,另一个线程可能会取消设置布尔值的值)。 基本上,只要您具有并发性和可变状态,就需要对幂等性进行更仔细的考虑。

幂等性通常是构建健壮系统的有用属性。 例如,如果存在从第三方接收重复消息的风险,则使消息处理程序充当幂等操作会很有帮助,这样消息效果只会发生一次。

<think>我们正在讨论模运算(Modular Exponentiation),这是一种在密码学(尤其是RSA算法)中至关重要的运算。模运算指的是计算形如 \( a^b \mod m \) 的表达式,其中 \( a \) 是底数,\( b \) 是指数, \( m \) 是模数。其核心挑战在于当 \( a, b, m \) 非常大时(例如在RSA中,\( b \) 可能是一个2048位的整数),直接计算 \( a^b \) 再取模是不可行的,因为 \( a^b \) 会超出计算机的整数表示范围。因此,我们需要高效的算法。 ### 一、模运算的数学原理 模运算基于以下模运算的性质: 1. **乘法性质**: \( (a \times b) \mod m = [(a \mod m) \times (b \mod m)] \mod m \) 2. **运算性质**: \( a^b \mod m \) 可以通过将指数 \( b \) 分解为二进制形式,然后利用平方和乘法逐步计算。 ### 二、快速算法(平方乘算法) 快速算法(也称为平方乘算法)将指数 \( b \) 表示为二进制形式,例如 \( b = (b_k b_{k-1} \dots b_1 b_0)_2 \),其中 \( b_i \) 是二进制位(0或1)。那么: \[ a^b = a^{\sum_{i=0}^{k} b_i \cdot 2^i} = \prod_{i=0}^{k} \left( a^{2^i} \right)^{b_i} \] 因此,我们可以通过迭代的方式计算: - 从结果 \( res = 1 \) 开始。 - 遍历指数 \( b \) 的每一个二进制位(从最低位到最高位): - 如果当前位为1,则将结果乘以当前的底数 \( a \) 并取模 \( m \)。 - 然后将底数平方并取模 \( m \)(因为 \( a^{2^{i+1}} = (a^{2^i})^2 \))。 - 指数右移一位(相当于除以2)。 **算法步骤**: 1. 初始化结果 \( res = 1 \)。 2. 将底数 \( a \) 对 \( m \) 取模(减少计算量)。 3. 当指数 \( b > 0 \) 时循环: - 如果 \( b \) 是奇数(即最低位为1),则 \( res = (res \times a) \mod m \)。 - 将 \( a \) 平方: \( a = (a \times a) \mod m \)。 - 将 \( b \) 右移一位(即 \( b = b // 2 \))。 4. 返回 \( res \)。 **时间复杂度**:由于指数 \( b \) 的二进制位数是 \( \log_2 b \),所以循环执行 \( O(\log b) \) 次,每次执行常数次乘法和取模运算。因此,总时间复杂度为 \( O(\log b) \),这对于大指数非常高效。 ### 三、模运算在密码学中的应用 在RSA加密和解密过程中,核心操作就是模运算- **加密**: \( c = m^e \mod n \) - **解密**: \( m = c^d \mod n \) 其中 \( e \) 和 \( d \) 都是非常大的数(通常1024位以上),因此必须使用快速算法。 此外,模运算的逆问题(即已知 \( a, m \) 和 \( a^b \mod m \),求 \( b \))称为**离散对数问题**,目前没有已知的多项式时间算法求解(在经典计算机上),这构成了公钥密码学(如Diffie-Hellman密钥交换、ElGamal加密)的安全基础[^1]。 ### 四、实现示例 以下是用C语言实现的快速算法(模运算): ```c #include <stdio.h> // 函数:计算 a^b mod m long long mod_exp(long long a, long long b, long long m) { long long res = 1; a = a % m; // 先取模,确保a<m while (b > 0) { // 如果b是奇数,则乘上当前的a if (b % 2 == 1) { res = (res * a) % m; } // 将指数右移一位(相当于除以2) b = b >> 1; // 将底数平方 a = (a * a) % m; } return res; } int main() { long long a = 2, b = 10, m = 1000; printf("%lld^%lld mod %lld = %lld\n", a, b, m, mod_exp(a, b, m)); // 输出 2^10 mod 1000 = 24 return 0; } ``` ### 五、注意事项 1. **大整数处理**:在实际密码学应用中,\( a, b, m \) 可能非常大(例如2048位),因此需要使用大整数库(如GMP)来避免溢出。 2. **常数时间实现**:在安全敏感的场景中,算法执行时间不应泄露指数 \( b \) 的信息(例如,避免通过时间侧信道攻击推断私钥)。因此,需要实现常数时间的快速算法(通常通过固定循环次数和避免条件分支来实现)。 3. **算法优化**:进一步优化包括使用蒙哥马利约简(Montgomery Reduction)来加速模乘运算。 ### 总结 模运算是密码学中的基础运算,其高效实现依赖于快速算法。该算法通过指数的二进制分解,将乘法和取模操作控制在 \( O(\log b) \) 次,从而能够处理极大的指数。在RSA、Diffie-Hellman等公钥密码系统中,模运算直接关系到系统的安全性和效率。 §§相关问题§§ 1. 如何用快速算法计算矩阵的? 2. 离散对数问题在密码学中还有哪些应用? 3. 如何优化模运算以抵抗侧信道攻击? 4. 在RSA算法中,为什么选择65537作为公钥指数? 5. 除了快速算法,还有哪些方法可以计算大数的模?</think>### 模运算的数学原理与实现详解 模运算(Modular Exponentiation)是密码学中的核心运算,指计算形如 \( a^b \mod m \) 的表达式。其核心在于**高效计算大指数的模运算结果**,同时避免中间值溢出。下面从数学原理和实现方法两方面详细说明: --- #### 一、数学原理 1. **模运算性质** 模运算基于以下关键性质: \[ (a \times b) \mod m = [(a \mod m) \times (b \mod m)] \mod m \] 这一性质允许我们将大数运算分解为多个小数运算的组合[^1]。 2. **指数分解原理** 任意指数 \( b \) 可表示为二进制形式: \[ b = \sum_{i=0}^{k} b_i \cdot 2^i \quad (b_i \in \{0,1\}) \] 因此: \[ a^b = a^{\sum b_i \cdot 2^i} = \prod_{i=0}^{k} \left( a^{2^i} \right)^{b_i} \] 例如: \[ a^{11} = a^{8+2+1} = a^8 \times a^2 \times a^1 \] 3. **离散对数难题** 已知 \( a^b \mod m \) 求 \( b \) 是**离散对数问题**,在经典计算机上无多项式时间解法,这是公钥密码学的安全基础[^1]。 --- #### 二、快速算法实现 快速算法通过**二进制分解指数+迭代平方**实现 \( O(\log n) \) 时间复杂度: ##### 算法步骤(迭代法): 1. 初始化结果 \( res = 1 \) 2. 将底数 \( a \) 对 \( m \) 取模: \( a \leftarrow a \mod m \) 3. 当指数 \( b > 0 \) 时循环: - 若 \( b \) 为奇数: \( res \leftarrow (res \times a) \mod m \) - 将 \( a \) 平方: \( a \leftarrow (a \times a) \mod m \) - 将 \( b \) 右移一位: \( b \leftarrow b // 2 \) 4. 返回 \( res \) ##### 代码实现(C语言): ```c #include <stdio.h> int mod_exp(int base, int exp, int mod) { int res = 1; base %= mod; // 初始取模 while (exp > 0) { if (exp & 1) // 指数为奇数 res = (res * base) % mod; base = (base * base) % mod; // 底数平方 exp >>= 1; // 指数右移 } return res; } int main() { printf("2^10 mod 1000 = %d\n", mod_exp(2, 10, 1000)); // 输出 24 return 0; } ``` ##### 示例计算 \( 3^{13} \mod 7 \): | 步骤 | 指数 \( b \) (二进制) | \( a \) | \( res \) | |------|------------------------|---------|--------------------| | 初始 | 1101 (13) | 3 | 1 | | 1 | 1101 (奇) | 3 | \( 1×3 \mod 7=3 \) | | | 右移→110 | \( 3^2 \mod 7=2 \) | | | 2 | 110 (偶) | 2 | 3 | | | 右移→11 | \( 2^2 \mod 7=4 \) | | | 3 | 11 (奇) | 4 | \( 3×4 \mod 7=5 \) | | | 右移→1 | \( 4^2 \mod 7=2 \) | | | 4 | 1 (奇) | 2 | \( 5×2 \mod 7=3 \) | | 结果 | | | **3** | --- #### 三、密码学中的应用 1. **RSA加密/解密** - 加密: \( c = m^e \mod n \) - 解密: \( m = c^d \mod n \) 依赖快速处理大指数(如2048位)[^1][^3]。 2. **Diffie-Hellman密钥交换** 计算 \( g^{ab} \mod p \) 建立共享密钥,其中 \( a,b \) 为私钥。 3. **数字签名** DSA和ECDSA签名验证涉及模运算--- #### 四、关键优化技术 1. **蒙哥马利约简** 通过预计算加速模乘运算,适用于硬件实现。 2. **滑动窗口法** 将指数分组处理,减少乘法次数(如处理连续0比特)。 3. **中国剩余定理(CRT)** 在RSA解密中,将运算分解为: \[ m = [ (c^{d_p} \mod p) \cdot q \cdot q^{-1} + (c^{d_q} \mod q) \cdot p \cdot p^{-1} ] \mod n \] 速度提升4倍[^3]。 --- #### 五、安全性注意事项 1. **侧信道攻击防御** - 常数时间实现:避免条件分支泄露指数信息 - 盲化技术:添加随机数掩码 2. **大数选择原则** - 模数 \( m \) 至少2048位 - 指数 \( b \) 需足够大(如RSA中 \( e>2^{16} \)) > 快速算法将指数运算从 \( O(n) \) 优化到 \( O(\log n) \),使1024位RSA解密在普通CPU上仅需毫秒级[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值