C ++与C#计算(错误结果)

时间:2015-06-08 19:07:45

标签: c# c++ math

我有一点问题;

我有这个C ++计算:

int main(unsigned long pass){

char name[50];

cout << "Enter username please: " << endl << endl;
gets_s(name);
cout << "\n";

pass = strlen(name);
pass = pass * 3;
pass = pass << 2;
pass = pow(pass, 3.0);
pass = pass + 23;
pass = pass + (pass * 708224);

cout << "Your generated serial: " << +pass << endl << endl;

system("pause");}

这为我提供了3个字符用户名的工作代码。

这是我的C#计算。

private void btn_generate_Click(object sender, EventArgs e)
    {
        pass = txt_user.TextLength;           
        pass = pass * 3;
        pass = pass << 2;
        pass = pass * pass * pass;
        pass = pass + 23;
        pass = pass + (pass * 708224);

        txt_serial.Text = pass.ToString();
    }

这给了我完全相同用户名的错误代码..

奇怪的是,两者的计算给出了相同的结果,直到这一行:

pass = pass + (pass * 708224);

在此计算之后,C#给出了错误的结果。

c ++结果:2994463703(正确)

c#results:33059234775(错误)

我希望有人可以解释一下。

2 个答案:

答案 0 :(得分:2)

所以,这里有三个(至少)潜在问题。

  1. 此算法呈指数级增长,并提供针对任何内容的保护。它很容易逆转,不会尝试确保输入。
  2. pow(pass, 3.0)方法 以返回double
  3. long数据类型(在C ++中)并不总是 64位。它可以 32位。
  4. 如果我们忽略第一点,并跳到第二点,则有两个潜在的问题:

    1. pow(pass, 3.0)行被点击时,由于浮点错误,可能并不总是返回相同的值。 (现在,我不怀疑这是您的代码中的一个主要问题,但您没有考虑到它。)
    2. pass + (pass * 708224)行(可以重写为pass * 708225 fyi)被命中时,在32位C ++环境中,它将静默溢出到值{{ 1}},恰好是您的C ++结果。
    3. 那么,你如何解决这个问题?

      修复该算法。就目前而言,您可以轻松构建潜在值的查找表。

      2,994,463,703

      现在,问题不在于这些数字总是将是相同的,这通常是预期的。问题是实际适合Input (pass) Output 1 1,240,154,505 2 9,806,791,575 3 33,059,234,775 4 78,340,308,375 5 152,992,889,175 etc. etc. 唯一值是第一个。一旦计算出第二个字符,它就会超出潜在范围。如果您要在C ++中执行此操作,则应该尽量避免使用Int32数据类型。它们并不总是保证是64位。

      如果您需要序列哈希(正如我们在现实世界中所称),我建议您查看long,{{1或任何其他哈希算法。 (这里提到的所有三个都内置在.NET中,应该很容易将它们用于C ++。)

      如何判断我的C ++环境是否支持64位md5变量?

      很简单,使用sha1/2unsigned long)的最大值为unsigned long种子,添加一个值,然后检查该值是否小于1.

      unsigned int

      结果应为4,294,967,295unsigned long test = 4294967295; test = test + 1; bool longIs64Bits = test > 0; 。如果是true,则您拥有64位false类型。如果true,那么你不会。

      如果我真的需要64位数字怎么办?

      幸运的是,C ++还提供了unsigned long变量类型。 (以及false。)注意:这些数据类型的大小可能会有所不同,但不小于 64位。

      long long

      前面的代码段应始终为真。

      最后,unsigned long long中还定义了unsigned long long test = 4294967295; test = test + 1; bool longLongIs64Bits = test > 0; 。这保证是64位。它是C99规范和C ++ 11规范的一部分,但我无法保证支持它。

答案 1 :(得分:0)

EBrown是正确的,C ++代码需要认真重新思考,但如果C ++代码是遗留的而你无法改变它,那么你能做的最好就是复制C#版本中的bug。

在c#版本中使用uint而不是long来触发无符号32位溢出。

您无法可靠地复制双舍入错误。使用Math.pow并祈祷它永远不会出现。

编辑: 附录:朋友不要让朋友们自己加密。