You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何仅用算术运算实现整数区间截断函数?

如何仅用算术运算实现整数区间截断函数?

当然可以做到!你要的这个其实就是整数场景下的钳位(clamp)函数——把输入X限制在[L, M]区间内,低于L返回L,高于M返回M,中间返回自身。而且完全不需要逻辑运算符,纯靠加减乘除、平方根这些算术操作就能实现,我给你一步步拆解:

核心思路:用算术实现「取大/取小」

要实现区间截断,我们可以分两步走:

  1. 先把X“拉”到不低于L的位置(也就是取X和L的最大值)
  2. 再把第一步的结果“压”到不超过M的位置(也就是取这个结果和M的最小值)

而关键就在于,怎么用算术实现「取两个数的最大值/最小值」——这时候我们可以利用绝对值的特性:对于任意整数a和b,max(a,b) = (a + b + |a - b|) / 2min(a,b) = (a + b - |a - b|) / 2

举个例子验证下:比如a=1,b=3,max(1,3)=(1+3+2)/2=6/2=3,正确;min(1,3)=(1+3-2)/2=2/2=1,正确。再比如a=-4,b=0,max(-4,0)=(-4+0+4)/2=0/2=0,正确;min(-4,0)=(-4+0-4)/2=-8/2=-4,正确。

用算术实现绝对值

那绝对值|n|怎么用算术表示?对于整数n来说,|n| = sqrt(n²)——因为任何整数平方后都是非负的,开平方根就得到它的绝对值,完全符合要求。

组合成最终的截断函数

把上面的内容组合起来,先实现「X和L的最大值」,再把这个结果和M取最小值,就能得到我们要的截断函数:

首先,max(X, L) = (X + L + sqrt( (X - L)² )) / 2

然后,把这个结果代入min函数,得到最终的clamp表达式:

clamp(X, L, M) = ( max(X,L) + M - sqrt( (max(X,L) - M)² ) ) / 2

把max(X,L)的表达式替换进去,就是完整的纯算术式子:

clamp(X, L, M) = [ (X + L + sqrt( (X - L)² )) / 2 + M - sqrt( ( (X + L + sqrt( (X - L)² )) / 2 - M )² ) ] / 2

用你的例子验证

拿你给的L=0、M=3的例子测试:

  • 当X=-4时:
    max(-4,0) = (-4 + 0 + sqrt( (-4-0)² )) /2 = (-4 + 0 +4)/2=0/2=0
    然后clamp结果=(0 +3 - sqrt( (0-3)² ))/2=(3-3)/2=0,符合规则1
  • 当X=4时:
    max(4,0)=(4+0+4)/2=8/2=4
    clamp结果=(4+3 - sqrt( (4-3)² ))/2=(7-1)/2=6/2=3,符合规则2
  • 当X=2时:
    max(2,0)=(2+0+2)/2=4/2=2
    clamp结果=(2+3 - sqrt( (2-3)² ))/2=(5-1)/2=4/2=2,符合规则3

完美契合所有要求!

补充细节

这里的除法都是整数除法(也就是截断向零,因为所有分子都是偶数:比如a+b+|a-b|,当a≥b时,等于a+b+a-b=2a,是偶数;当a<b时,等于a+b+b-a=2b,也是偶数,所以除以2的结果必然是整数),完全符合整数运算的要求。

如果不想用平方根,其实还有一种纯整数算术的绝对值实现:对于非零整数n,|n| = n² // n(整数除法),n=0时|n|=0。不过这种方法要单独处理n=0的情况,但在我们的clamp函数里,当X=L或X=M时,对应的差值为0,这时候(a + b - |0|)/2=(a+b)/2,而X=L时max(X,L)=L,带入后结果正确,所以也可以用这个方法替换平方根,全程只用加减乘除和整数除法。

备注:内容来源于stack exchange,提问作者Rafael

火山引擎 最新活动