C# 验证大整数(BigInteger)的二进制模式

C# 验证大整数(BigInteger)的二进制模式,c#,.net,binary,numbers,bit-manipulation,C#,.net,Binary,Numbers,Bit Manipulation,我想测试一个正整数,看看它的二进制表示形式是从零或多个1开始,然后是一个或多个0 00000000 // Valid 10000000 // Valid 11000000 // Valid 11100000 // Valid 11110000 // Valid 11111100 // Valid 11111110 // Valid 11111110 // Valid 11111111 // Not Valid // Any other combination is Not Valid 与正则表

我想测试一个正整数,看看它的二进制表示形式是从零或多个1开始,然后是一个或多个0

00000000 // Valid
10000000 // Valid
11000000 // Valid
11100000 // Valid
11110000 // Valid
11111100 // Valid
11111110 // Valid
11111110 // Valid
11111111 // Not Valid
// Any other combination is Not Valid
与正则表达式相同的表达式是^[1]*[0]+$。当然,这只是为了澄清,我们不能使用正则表达式

蛮力接近:

  • 创建多个位掩码,并一起确定结果
  • 使用动态掩码循环每个数字以确定结果
问题是我处理的是巨大的正整数,可能有数十万个数字,需要对数千个这样的数字进行测试

有没有更有效的方法来确定这种二进制模式

更新

这是我尝试的实现。还没有将时间与其他答案进行比较

public static bool IsDiagonalToPowerOfTwo (this System.Numerics.BigInteger number)
{
    byte [] bytes = null;
    bool moreOnesPossible = true;

    if (number == 0) // 00000000
    {
        return (true); // All bits are zero.
    }
    else
    {
        bytes = number.ToByteArray();

        if ((bytes [bytes.Length - 1] & 1) == 1)
        {
            return (false);
        }
        else
        {
            for (byte b=0; b < bytes.Length; b++)
            {
                if (moreOnesPossible)
                {
                    if (bytes [b] == 255)
                    {
                        // Continue.
                    }
                    else if
                    (
                        ((bytes [b] & 128) == 128) // 10000000
                        || ((bytes [b] & 192) == 192) // 11000000
                        || ((bytes [b] & 224) == 224) // 11100000
                        || ((bytes [b] & 240) == 240) // 11110000
                        || ((bytes [b] & 248) == 248) // 11111000
                        || ((bytes [b] & 252) == 252) // 11111100
                        || ((bytes [b] & 254) == 254) // 11111110
                    )
                    {
                        moreOnesPossible = false;
                    }
                    else
                    {
                        return (false);
                    }
                }
                else
                {
                    if (bytes [b] > 0)
                    {
                        return (false);
                    }
                }
            }
        }
    }

    return (true);
}
public static bool是对角线拓扑幂函数two(this System.Numerics.biginger number)
{
字节[]字节=null;
bool-moreonespobsible=true;
如果(数字==0)//00000000
{
return(true);//所有位都为零。
}
其他的
{
字节=数字。ToByteArray();
if((字节[bytes.Length-1]&1)==1)
{
返回(假);
}
其他的
{
for(字节b=0;b0)
{
返回(假);
}
}
}
}
}
返回(真);
}

在最坏的情况下,如果没有存储有关输入的额外数据,则不能比O(n)算法更好,其中n是位数,因为需要检查数字中的每一位

如果您可以在以前的操作中跟踪例如“最右边的1”和“最左边的0”,您可以通过检查它们是否确实是“10”立即获得答案


否则,您将不得不有效地迭代位以检查它是否正确。请注意,从左到右的数字都是1,然后检查所有的值都是0(使用适当的角型)就是O(n),而拥有完整的O(n)可能值列表并检查它是否等于(大概是?)O(n)比较中的任何值就是O(n^2)因此这是个坏主意。

将二进制数据划分为固定大小的块。。。32位。。。64位->将其视为无符号整数

准备两个包含所有有效模式和反向模式(以“0”开始,以“1”结束)的哈希映射。。。又是无符号整数

现在测试最左边的块是否包含在反向模式hashmap中。。。如果没有->模式无效
现在测试最右边的(非零)块是否包含在正常模式hashmap中。。。如果不是->模式无效


现在测试所有其他块是否等于所有位集模式(这应该是与无符号整数的比较)。。。如果全部相等->模式有效。。。其他的模式无效

假设整数以二进制形式存储,分组为无符号整数的数组x[],则可以执行以下操作:

Define UINT to be the unsigned integer type you are using for the grouped bits.
Define UMAX to be the maximum value of that type (all bits are on).

// Find first word that has a zero bit.
int i;
for (i = highest word in x; 0 <= i; --i)
    if (x[i] != UMAX)
        break;

// Return true if all bits in all of x[] are on.
if (i < 0)
    return true;

// Test whether word conforms to the ones-then-zeroes rule.
UINT y = x[i];
if (y + (y & -y))
    return false;

// Test whether all remaining words are zero.
for (; 0 <= i; --i)
    if (x[i])
        return false;

return true;
将UINT定义为用于分组位的无符号整数类型。
将UMAX定义为该类型的最大值(所有位均打开)。
//查找第一个具有零位的单词。
int i;

对于(i=x中最高的字;0)您实际上是将它们用作整数,还是用作位存储?坦率地说,如果这些是唯一有效的集合,我将使用不同的表示,即“1的数量,0的数量”当然,如果你需要做算术等,那就不行了。我不知道什么是休谟大整数,它是如何在.net上表示的?我想是ubyte/uint/etc数组……是这样吗?@MarcGravel已经问过了,但是,你是在用这些数据做算术,还是只是一种表示?@devundef:我错了。它应该是巨大的E、 提示:不要使用扩展方法,每次调用该方法时,都会在内存中生成一个大整数的副本;请尽可能使用“ref”。谢谢。我将尝试这两种方法,并回复到和使用预定义掩码128、192、224、240、252和254.Ve的从左到右字节数组掩码相比有多大的改进y优雅:y+(y&-y)。我在回答中使用了。谢谢。BigInteger类公开了ToByteArray函数。转换为long/ulong等数组会导致额外的开销。有什么理由你的函数不应该在字节数组上工作吗?我的回答是以大小无关的方式编写的;它假设一个无符号整数数组。这些整数可以是8位32-位或其他大小。尽管如此,使用较大的单元大小(对于机器来说是自然的),可能会有更好的性能。将字节数组转换为32位或64位整数数组实际上不应更改任何数据或移动任何内存。这只是一个语义问题,需要在编译器中处理,例如casti