Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在经过几次乘法**和溢出**后,是否可能获得数字的原始值?_C++_C_Algorithm_Hash_Modular - Fatal编程技术网

C++ 在经过几次乘法**和溢出**后,是否可能获得数字的原始值?

C++ 在经过几次乘法**和溢出**后,是否可能获得数字的原始值?,c++,c,algorithm,hash,modular,C++,C,Algorithm,Hash,Modular,总结:有没有办法做到这一点?我的意思是:假设我有一个无符号整数。然后我将它乘以几次(这里有溢出,,这是预期的)。那么是否可以“还原”原始值 详情如下: 都是关于你的。我需要做的是:我有一个长字符串的散列-例如:“abcd”。然后我得到了一个较短子字符串的哈希值,例如“cd”。如何使用给定的两个散列计算O(1)的“ab”散列 我现在的算法是: hash_t fast_pow( hash_t source, hash_t pow ) { if( 0 == pow ) {

总结:有没有办法做到这一点?我的意思是:假设我有一个无符号整数。然后我将它乘以几次(这里有溢出,,这是预期的)。那么是否可以“还原”原始值


详情如下:

都是关于你的。我需要做的是:我有一个长字符串的散列-例如:“abcd”。然后我得到了一个较短子字符串的哈希值,例如“cd”。如何使用给定的两个散列计算O(1)的“ab”散列

我现在的算法是:

hash_t fast_pow( hash_t source, hash_t pow )
{
    if( 0 == pow )
    {
        return 1;
    }

    if( 0 != pow % 2 )
    {
        return source * fast_pow( source, pow - 1 );
    }
    else
    {
        return fast_pow( source * source, pow / 2  );    
    }

}
  • 从“abcd”散列中减去“cd”散列(从多项式中删除最后的元素)
  • 通过
    p^len(“cd”)
    划分“abcd”散列,其中
    p
    是基数(素数)
这就是:

a*p^3+b*p^2+c*p^1+d*p^0
-abcd

c*p^1+d*p^0
-cd

ab获取:

( ( a * p ^ 3 + b * p ^ 2 + c * p ^ 1 + d * p ^ 0 ) - ( c * p ^ 1 + d * p ^ 0 ) ) / ( p ^ 2 ) = a * p ^ 1 + b * p ^ 0 ( (a*p^3+b*p^2+c*p^1+d*p^0)- (c*p^1+d*p^0) ) /(p^2) =a*p^1+b*p^0 如果我没有溢出(如果
p
是一个小数字),这就行了。但是如果它不-它不工作

有什么把戏吗


另外,
c++
标记是因为数字溢出,因为它是特定的(并且不同于python、scheme或其他东西)

所以溢出实际上就是你的编译器对你很好;C/+++标准实际上表明溢出是未定义的行为。所以一旦你飞越了,实际上你什么都做不了,因为你的程序不再是确定性的


您可能需要重新考虑算法,或者采用模运算/减法来修正算法。

不知道溢出部分,但有一种方法可以恢复原始值

中国剩余定理帮助很大。让我们调用
h=abcd-cd
。G是值,
h
,没有溢出,
G=h+k*2^32
,假设溢出只发生
%2^32
。因此,
ab=G/p^2

G = h (mod 2^32)
G = 0 (mod p^2)
如果p^2和2^32是互质。这一页上,给我们

G = h * b * p^2 (mod 2^32 * p^2)
其中,
b
是p^2模2^32的模乘逆,
b*p^2=1(mod 2^32)
。计算
G
后,只需除以
p^2
即可找到
ab


我希望我没有犯任何错误…

您应该使用无符号整数来定义溢出行为(模2^N)。有符号整数溢出未定义


同样,你应该用p模的乘法逆乘以适当的值,而不是除以。例如,如果p=3且散列值为8位,则乘以171,因为171*3=513=2*256+1。如果p和模值是相对素数,则存在乘法逆。

这里只是一个部分的答案:我认为严格来说,不必使用无符号整数。你可以用

但是请注意,对于-0和+0,这将有一个单独的表示形式,并且您可能需要在此过程中手工编码算术运算


某些处理器指令与整数表示无关,但并非所有指令。

您有一个*b=c mod 2^32(或根据您的哈希处理方式修改其他指令)。如果你能找到d,使得b*d=1模2^32(或者其他模),那么你可以计算a*b*d=a 并检索a。如果gcd(b,mod 2^32)=1,则可以使用来查找x和y,使b*x+2^32*y=1,或 b*x=1-y*2^32,或
b*x=1 mod 2^32,因此x是要乘以的数字。

扩展欧几里德算法是一个很好的解决方案,但它太复杂且难以实现。有一个更好的


还有另一种方法可以做到这一点(感谢我的电子朋友(:)

在-模乘逆中有一篇很好的文章,在
m
a
是互质的情况下使用了欧拉定理:

其中
φ(m)

在我的例子中,
m
(模)是散列类型的大小-
2^32
2^64
,等等(在我的例子中是64位)。
这意味着,我们应该只找到φ(m)的值,但是考虑一下-
m==2^64
,这就保证了
m
将是所有奇数的互质,而不是任何偶数的互质。所以,我们需要做的是得到所有值的数目,并将它们除以2

此外,我们知道,
m
将是未签名的,否则我们将遇到一些问题。这给了我们这样做的机会:

hash_t x = -1;
x /= 2;
hash_t a_reverse = fast_pow( a, x );
嗯,大约64位的数字,
x
确实是一个很大的数字(19位:
922372036854775807
),但是
fast\u pow
非常快,我们可以缓存反向数字,以防我们需要多个查询

fast\u pow
是一种众所周知的算法:

hash_t fast_pow( hash_t source, hash_t pow )
{
    if( 0 == pow )
    {
        return 1;
    }

    if( 0 != pow % 2 )
    {
        return source * fast_pow( source, pow - 1 );
    }
    else
    {
        return fast_pow( source * source, pow / 2  );    
    }

}

补充:例如:

    hash_t base = 2305843009213693951;  // 9th mersenne prime
    hash_t x = 1234567890987654321;

    x *= fast_pow( base, 123456789 );   // x * ( base ^ 123456789 )

    hash_t y = -1;
    y /= 2;
    hash_t base_reverse = fast_pow( base, y );

    x *= fast_pow( base_reverse, 123456789 );   // x * ( base_reverse ^ 123456789 )
    assert( x == 1234567890987654321 ) ;

完美且非常快速。

对于
p=2
这是不可能的。对于所有其他素数
p
,这是可能的…@Sven Marnach-嗯,怎么做?我不能减去最后一个字母,然后除以基数(
p
),再减去前面的最后一个字母,再除以
p
,等等,因为我不知道字符串,但只知道它们的哈希值。@Sven Marnach-还有,有什么可能?要“还原”数字还是用来计算散列?如果是第二个,我想我需要接受cnicutar的答案,并提出关于散列的新问题?它是无符号整数,我刚刚编辑了这个问题。嗯,听起来很合理,但我知道,找到这样的逆元素绝非一个简单的问题,而且会让事情变慢..+1。我会考虑一个关于这一点。无符号值不会溢出。你的答案是什么