给定一个大整数(以二进制形式存储),如何快速测试它是否为2的幂,即对于整数指数k等于2?
一种简单但相当慢的方法是连续除以2直到数字变为2或者存在非零余数。不幸的是,我们需要执行尽可能多的分区,因为我们的号码中有数字。
对于小整数,有许多解决方案,包括位计数等。我对任意位数的整数的快速解决方案感兴趣。例如。我们可以通过一些快速整数除以2或其他技巧加速上述方法吗?
答案 0 :(得分:10)
我认为最快的方法仍然是检查这些位。假设你的数字是x,在java中你可以x & (x - 1) == 0
如果是真的那么它就是2的幂
对于BigInteger,您可以执行x.and(x.subtract(BigInteger.ONE)).equals(BigInteger.ZERO)
答案 1 :(得分:2)
因为您只需要验证整个大整数的位数是否为1
,我想最快的方法可能是将大整数存储为uint32_t
或更好{{1}的数组所以你可以使用popcnt
x86指令。
还有一些天真的方法,如使用SSE3指令uint64_t
所描述的here,甚至other approaches仍然依赖于PSHUFB
,但手写程序集。
当然这可能是矫枉过正,因为你不需要人口数量,但是你需要知道它是否正好是1但是它可能值得尝试。
与此类优化问题一样,猜测只是无关紧要,唯一的选择是测试不同的方法,看看哪种方法更合适。
答案 2 :(得分:2)
从大数字中减去<html>
<head>
</head>
<body>
<?php
$con = mysql_connect('localhost', 'root', '');
if (!$con){
die("Can not connect: " . mysql_error());
}
mysql_select_db("form_process", $con);
$sql = "SELECT * FROM `form_submissions`";
$myData = mysql_query($sql,$con);
echo "<table border=1>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Phone Number</th>
<th>Class interested in</th>
</tr>";
while($row= mysql_fetch_array($result)){
echo "<tr>";
echo "<td>" . $record['First'] . "</td>";
echo "<td>" . $record['Last'] . "</td>";
echo "<td>" . $record['Phone'] . "</td>";
echo "<td>" . $record['Class'] . "</td>";
echo "</tr>";
}
echo "</table>";
mysqli_close();
?>
</body>
</html>
是不理想的,因为在CPU级别会有多个操作,包括大数字的进位,因为计算不适合累加器。
对于CPU上的计算,最快的方法是:
1
指令)LOAD
指令)CMP
指令)JNZ
(1 1
指令)SUB
指令)AND
指令)要进行优化,您需要将数字拆分为这些集合并进行比较。
上述方法的关键优势在于:通过步骤(2),我们摆脱了大的减法和携带。步骤(4)中的减法将只接受一条指令,并且与零的比较也将采用一条指令。所以它应该加快操作。
答案 3 :(得分:1)
对于非常大的数字,这个测试基本上等于将所有字节比较为零,除了其中一个必须保持2的幂。我们可以专注于此测试为零,而有效地检查非零则不那么重要。
最简单的形式是测试32或64位整数(即4或8字节)为零(取决于寄存器大小)。
通过SIMD介绍可以更快地实现。在SSE2或AVX下,您可以获取16或32个字节,与零(_mm256_cmpeq_epi8
/ _mm256_cmpeq_epi8
与预清除寄存器进行比较)并使用_mm_movemask_epi8
或{打包到16或32位{1}}。然后,将得到的标量(short或int)与所有标量进行比较。
[不幸的是,在AVX512中似乎没有相应的_mm256_movemask_epi8
,这样一次就可以处理64个字节。]
如果您发现一组字节保存非零值,您可以使用256个条目的查找表逐个测试它们。
使用SIMD方法,您甚至可以通过另一个256个条目的查找表来提高速度,这些条目告诉一个字节中非零位的索引,或者当有几个非零位时保留值。使用此查找表两次或四次,您将知道16或32位中的哪一位对应于非零字节(并且还检测到几个非零字节)。
利用公式_mm512_movemask_epi8
的解决方案也是可能的。
正如已经说过的,这些微观优化可能毫无价值,除非你的大部分数字不是2的幂。