检查一个数是不是可​​以表示为 x 的 2 次方之和?

Posted

技术标签:

【中文标题】检查一个数是不是可​​以表示为 x 的 2 次方之和?【英文标题】:check wheather a number can be expressed as sum of x powers of two?检查一个数是否可​​以表示为 x 的 2 次方之和? 【发布时间】:2021-09-14 14:26:50 【问题描述】:

是否有任何小技巧可以检查一个数字是否可以表示为 2 的 x 次方之和? 例如:x=3 n=21 数字是 16,4,1 如果 n=30 它应该是假的,因为没有 3 的 2 的幂来表示 30

【问题讨论】:

如果 2 的所有次方都必须不同,则 n 是 2 的 x 次方之和,当且仅当 n 的二进制展开中有 x 个设置位。 如果它们不必不同怎么办? 您的问题似乎是关于数学而不是编程;您可能会在数学网站而不是编程网站上得到更好的答案。我认为我的评论可以更进一步:如果二进制扩展或 n 中有超过 x 个设置位,则 n 不能表示为 x 次方或 2 的总和,即使它们被允许相同。另一方面,如果例如 n = 9 = 2^3 + 2^0(两个设置位),我们可以根据需要将其写为 2^2 + 2^2 + 2^0。祝你好运。 谢谢,在一些实验之后真的有帮助未设置,因为您始终可以根据需要添加 2^0 【参考方案1】:

对于一个数字 n……

… 最小 x 是 n 中 1 位的数量。这个数字称为 popcount(n)。 示例:二进制数 0b1011 至少需要 popcount(0b1011)=2 的 3 次方相加 (0b1000+0b0010+0b0001)。 … 最大 x 为 n。因为1 是 2 的幂,所以您可以将 1 添加 n 次得到 n。

现在是一个难题。如果 x 在 popcount(n) 和 n 之间怎么办? 事实证明,所有这些 x 都是可能的。构建两个的 x 次方的总和……

从最短的和(n 的二进制表示)开始 如果您的加数少于 x,则将任何大于 1 的加数拆分为两个加数,将加数的数量加一。这可以在您到达 x=n 之前完成。

示例:11=0b1011 可以表示为 x=7 的 2 次方之和吗?

是的,因为 popcount(n)=3

我们使用 x=7 的 2 次方求和 11 = 0b1011 = 0b1000+0b10+0b1 |只有3个加数,所以拆分一个 = (0b100+0b100)+0b10+0b1 |只有 4 个加数,所以再拆分一个 = ((0b10+0b10)+0b100)+0b10+0b1 |只有 5 个加数,所以再拆分一个 = (((0b1+0b1)+0b10)+0b100)+0b10+0b1 |只有 6 个加数,所以再拆分一个 = (((0b1+0b1)+(0b1+0b1))+0b100)+0b10+0b1 | 7个加法,完成

实施

为了实现检查»可以将 n 表示为 x 的 2 次方之和吗?« 使用

isSumOfXPowersOfTwo(n, x) 
   return x<=n && x>=popcount(n).

有关popcount 的有效位旋转实现,请参阅this question。一些处理器甚至有一个指令。

【讨论】:

以上是关于检查一个数是不是可​​以表示为 x 的 2 次方之和?的主要内容,如果未能解决你的问题,请参考以下文章

如何快速的计算出一个数的n次方

一个数的次方可以拆成两个数的次方相加么

如何用C语言实现2的n次方

c语言中2的次方怎么写怎么表示?

怎么巧判断一个整数是不是是2的n次方幂

判断一个数是否时2的整数次方