当前位置: 首页 > 面试题库 >

安全整数中间值公式

马沛
2023-03-14
问题内容

我正在寻找一个在Java中工作的有效公式,该公式可以计算以下表达式:

(low + high) / 2

用于二进制搜索。到目前为止,我一直使用“低+(高-低)/ 2”和“高-(高-低)/
2”来避免某些情况下的上溢和下溢,但不能同时使用这两种情况。现在,我正在寻找一种有效的方法来执行此操作,该方法适用于任何整数(假设整数范围为-
MAX_INT-1到MAX_INT)。

更新 :结合詹德和彼得·G。的答案,并进行了一段时间的实验,我得到了中间值元素及其直接邻居的以下公式:

最低中点(等于floor((low + high)/2)[2 3]-> 2,[2 4]-> 3,[-3 -2]-> -3)

mid = (low & high) + ((low ^ high) >> 1);

最高中点(等于ceil((low + high)/2)[2 3]-> 3,[2 4]-> 3,[-3 -2]-> -2)

low++;
mid = (low & high) + ((low ^ high) >> 1);

中点之前(等于floor((low + high - 1)/2))[2 3]-> 2,[2 4]-> 2,[-7 -3]-> -6)

high--;
mid = (low & high) + ((low ^ high) >> 1);

中点后(等于ceil((low + high + 1)/2))[2 3]-> 3,[2 4]-> 4,[-7 -3]-> -4)

mid = (low & high) + ((low ^ high) >> 1) + 1;

或者,在没有按位和(&)和或(|)的情况下,代码x >> 1会稍微慢一些(可以替换为floor(x / 2)以获取按位运算符自由的公式):

最左中点

halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);

最右边的中点

low++
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);

中点之前

high--;
halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1);

后中点

halfLow = (low >> 1), halfHigh = (high >> 1);
mid = halfLow + halfHigh + ((low-2*halfLow + high-2*halfHigh) >> 1) + 1;

注意 :以上>>运算符被认为是有符号移位。


问题答案:

来自http://aggregate.org/MAGIC/#Average%20of%20Integers:

(low & high) + ((low ^ high) / 2)

是两个无符号整数的防溢出平均值。

现在,此技巧仅适用于无符号整数。但是因为((a+x) + (b+x))/2 = (a+b)/2 + x,如果您具有与有符号整数相同的位大小的无符号整数,则可以按以下步骤进行伪造:

unsigned int u_low  = low + MAX_INT + 1;
unsigned int u_high = high + MAX_INT + 1;
unsigned int u_avg  = (u_low & u_high) + (u_low ^ u_high)/2;
int avg = u_avg - MAX_INT - 1;

更新
:经进一步思考,即使您没有带符号的整数,这也将起作用。按位,有符号和无符号整数等效于加,减和布尔运算。因此,我们需要担心的是确保除法行为像无符号除法一样,我们可以通过使用shift并屏蔽掉最高位来做到这一点。

low += MAX+INT + 1;
high += MAX_INT + 1;
avg = (low & high) + (((low ^ high) >> 1) & MAX_INT);
avg -= MAX_INT + 1;

(请注意,如果您使用的是Java,则可以使用无符号移位... >>> 1而不是(... >> 1) & MAX_INT。)

但是, 我偶然发现了一个更简单的选择,我还没有弄清楚它是如何工作的。无需通过MAX_INT调整数字或使用无符号变量或其他任何东西。很简单:

avg = (low & high) + ((low ^ high) >> 1);

与16位有符号整数所有组合进行试验low,并high在范围内-32768..32767,但尚未完全成熟(由我反正)。



 类似资料:
  • 将值转换为安全整数。 使用 Math.max() 和 Math.min() 来找到最接近的安全值。 使用 Math.round() 转换为一个整数。 const toSafeInteger = num => Math.round(Math.max(Math.min(num, Number.MAX_SAFE_INTEGER), Number.MIN_SAFE_INTEGER)); toSafe

  • 这篇文档介绍了Django自带的所有中间件组件。 要查看关于如何使用它们以及如何编写自己的中间件,请见中间件使用指导。 可用的中间件 缓存中间件 class UpdateCacheMiddleware[source] class FetchFromCacheMiddleware[source] 开启全站范围的缓存。 如果开启了这些缓存,任何一个由Django提供的页面将会被缓存,缓存时长是由你在C

  • Firebase Web-App指南指出,我应该将给定的放在Html中初始化Firebase: 通过这样做,就会公开给每个访问者。那把钥匙的用途是什么,它真的是要公开的吗?

  • Secure 中间件 Secure 中间件用于阻止跨站脚本攻击(XSS),内容嗅探,点击劫持,不安全链接等其他代码注入攻击。 使用 e.Use(middleware.Secure()) 自定义配置 用法 e := echo.New() e.Use(middleware.SecureWithConfig(middleware.SecureConfig{ XSSProtection:

  • 问题内容: 比较浮点数和这样的整数是否安全? 根据JLS(5.6.2。二进制数值提升),如果其中一个参数为,则另一个参数将转换为比较之前的值。但是据我了解,如果转换后的float与原始float二进制相同,则这样的比较将返回true。我们如何确保呢? 问题答案: 是的,您的具体示例很好,因为和都可以精确地表示为。 请注意,通常情况下并非如此:有很多大值无法完全表示为。例如,即使2_000_000_

  • 问题内容: 在web应用指南规定我应该把给定的在我的HTML初始化火力地堡: 这样一来,每个访问者都可以接触到。该密钥的目的是什么,真的意味着要公开吗? 问题答案: 此配置代码段中的apiKey只能识别您在Google服务器上的Firebase项目。知道它不是安全风险。实际上,他们有必要知道它,以便他们与Firebase项目进行交互。使用Firebase作为其后端的每个iOS和Android应用程