计算行列式并使用 uint64_t C 类型的除法和乘法

Computing determinant and using division and multiplication of uint64_t C type

这个问题已经过编辑以澄清它。

我有以下矩阵,在 [reteam.org/papers/e59.pdf] 的第 1 页中定义,用 R 表示法编写:

m1 = matrix(c(207560540,956631177,1,956631177,2037688522,1,2037688522,1509348670,1),ncol=3,byrow=T)

m1的行列式应该是2^31 -1的整数倍。

如已接受的答案所示,det(m1) 应为 -1564448852668574749。

然而,在 R 中,我得到了

> det(m1)
[1] -1564448852668573184

并且,手动使用一个简单的方程式:

> m1[1,1]*(m1[2,2]-m1[3,2]) - m1[2,1]*(m1[1,2] - m1[3,2]) + m1[3,1]*(m1[1,2]- m1[2,2])
[1] -1564448852668574720

如接受的答案所示,获得了正确的行列式 并由以下人员检查:

#include <inttypes.h>
#include <stdio.h>

int main() {

int64_t m1[3][3] = {{INT64_C(207560540) , INT64_C(956631177)   , INT64_C(1)},{ INT64_C(956631177), INT64_C(2037688522),       INT64_C(1)},{INT64_C(2037688522), INT64_C(1509348670) ,   INT64_C(1)}};                                                         

int64_t dm1 = m1[0][0]*(m1[1][1]-m1[2][1]) - m1[1][0]*(m1[0][1] - m1[2][1]) + m1[2][0]*(m1[0][1]- m1[1][1]);
int64_t divisor = (INT64_C(1)<<31) -1;
int64_t tmp = dm1/divisor;
int64_t check = tmp * divisor;

printf("dm1 == %" PRIu64"\n",dm1);
printf("(dm1/(2^31 -1))* %" PRIu64 " == %" PRIu64 "\n", divisor, check);

}

下面的文字是老问题。主要错误是使用了无符号类型。


我以前的最小非工作代码示例是:

  #include <inttypes.h>
  #include <stdio.h>

  int main() {

  uint64_t dm1 = 1564448852668573184;
  uint64_t divisor = (UINT64_C(1)<<31) -1; //powl(2,31)-1;
  uint64_t tmp = dm1/divisor;
  uint64_t check = tmp*divisor;                                                                                      

  printf("dm1 == %" PRIu64"\n",dm1);
  printf("(dm1/(2^31 -1))* %" PRIu64 " == %" PRIu64 "\n", divisor, check);
}

它的输出是

dm1 == 1564448852668573184

(dm1/(2^31 -1))* 2147483647 == 1564448850521091102

问题是第二行的值应该等于第一行的值。

我的错误是什么?我怎样才能完成这项工作?

出于与(使用整数)你得到 10 / 3 * 3 = 9 相同的原因。除法有余。 10 / 3 = 3,余数 1。当您乘以 3 时,余数将丢失,因此您得到 9 而不是 10.

在这种情况下,您的余数是 2147482082,当它与 1564448850521091102 相加时,得到 1564448852668573184。试试这个:

uint64_t dm1 = 1564448852668573184;
uint64_t divisor = (UINT64_C(1)<<31) -1; //powl(2,31)-1;
uint64_t tmp = dm1/divisor;
uint64_t remainder = dm1%divisor;
uint64_t check = tmp*divisor+remainder;  

你应该得到正确的结果。

分子不是除数的整倍数,所以有余数,商被截去

1564448852668573184 / 2147483647 = 728503266 remainder 2147482082

相乘,

2147483647 * 728503266 + 2147482082 = 1564448852668573184

编辑:

链接参考中显示的 3x3 矩阵的行列式是 -1564448852668574749。这可以被 2147483647 整除得到 -728503267.

所以你在某处发生了算术溢出。

答案:

您链接示例中矩阵行列式的值为负。请使用 int64_t 而不是 uint64_t.