C# 矩阵乘法的精度误差
在我的程序中编码一个矩阵乘法,我会得到精度错误(对于大型矩阵,结果不准确) 这是我的密码。当前对象的数据存储在扁平数组中,一行接一行。另一个矩阵B的数据存储在一个扁平数组中,一列接一列(所以我可以使用指针算法)C# 矩阵乘法的精度误差,c#,matrix,floating-point,double,precision,C#,Matrix,Floating Point,Double,Precision,在我的程序中编码一个矩阵乘法,我会得到精度错误(对于大型矩阵,结果不准确) 这是我的密码。当前对象的数据存储在扁平数组中,一行接一行。另一个矩阵B的数据存储在一个扁平数组中,一列接一列(所以我可以使用指针算法) protecteddouble[,]乘法(IMatrix B) { int columns=B.columns; int行=行; int size=列; 双精度[,]结果=新的双精度[行,列]; 对于(int row=0;row而不是双< /代码>。但是,这可能会导致性能下降,因此请先进
protecteddouble[,]乘法(IMatrix B)
{
int columns=B.columns;
int行=行;
int size=列;
双精度[,]结果=新的双精度[行,列];
对于(int row=0;row
事实上,代码有点复杂:我对几个块进行乘法运算(因此,我没有让I从0到大小,而是从localStart到localStop),然后对结果矩阵求和
我的问题:对于一个大矩阵,我得到了精度误差:
NUnit.Framework.AssertionException: Error at (0,1)
expected: <6.4209571409444209E+18>
but was: <6.4207619776304906E+18>
NUnit.Framework.AssertionException:在(0,1)处出错
预期:
但是:
有什么想法吗?哼哼,它并不能真正解决你的问题,但在NUnit中,你可以允许有一个精度误差并选择这个ε的值,它并不能真正解决你的问题,但在NUnit中,你可以允许有一个精度误差并选择这个ε的值作为起点,使用
double
无处不在而不是float作为起点,使用double
无处不在而不是float我最初说过应该将float
转换为double
。然而,正如您所指出的,这将破坏您的算法
你可以试试:
value += (double)*(mePtr++) * (double)*(bPtr++);
当前代码的一个问题是乘法是以浮点
精度进行的,然后添加到双精度
。先向double
施放将在一定程度上有所帮助
使用中间double
变量可能更清晰,但这取决于您
如果这不给你想要的精度,那么你需要考虑使用<代码>十进制< /代码>而不是<代码>双< /代码>。但是,这可能会导致性能下降,因此请先执行一些基准测试。
我最初说过,您应该将浮点值
转换为双倍值
。然而,正如您所指出的,这将破坏您的算法
你可以试试:
value += (double)*(mePtr++) * (double)*(bPtr++);
当前代码的一个问题是乘法是以浮点
精度进行的,然后添加到双精度
。先向double
施放将在一定程度上有所帮助
使用中间double
变量可能更清晰,但这取决于您
如果这不给你想要的精度,那么你需要考虑使用<代码>十进制< /代码>而不是<代码>双< /代码>。但是,这可能会导致性能下降,因此请先进行一些基准测试。
至少,您应该在整个过程中使用双精度测试。浮动是非常不精确的。至少,你应该在整个过程中使用双精度。浮动非常不精确。也许你所要做的就是使用浮动。但是你可以用浮点运算精确地得到一个特定的结果。也许你所要做的就是使用。但是你可以用浮点数学精确地得到一个特定的结果。这是一种称为“矩阵蠕变”的现象,如果你不一致地规范化你的矩阵,这种现象会在矩阵操作过程中逐渐发生。这是一种称为“矩阵蠕变”的现象这在矩阵操作过程中会逐渐发生,如果你不一致地规范化你的矩阵。结果只是。。。虫子。结果不是:
float* mePtr = ptrThis + row*rows;
float* bPtr = ptrB + col*columns;
我的行的正确索引器是:
float* mePtr = ptrThis + row * size;
float* bPtr = ptrB + col * size;
很抱歉,这里的答案不是很花哨。但是谢谢你的帮助 结果只是。。。虫子。结果不是:
float* mePtr = ptrThis + row*rows;
float* bPtr = ptrB + col*columns;
我的行的正确索引器是:
float* mePtr = ptrThis + row * size;
float* bPtr = ptrB + col * size;
很抱歉,这里的答案不是很花哨。但是谢谢你的帮助 当然,浮点数的精确度不如双倍点数。但是所有(好吧,几乎所有,我的统计是不准确的)浮点数都是不精确的。@High,double比float多29位精度。这使它们的精确度提高了约1亿倍。@Marcelo--确实如此。而且,我们中的许多人在进行严肃的数字运算时,不得不担心长时间运行的计算会导致精度下降。将浮动更改为双倍只会推迟问题,而不会消除问题。当然,有时它会将问题推迟到计算完成之后。当然,浮点数的精度不如双精度,这是肯定的。但是所有(好吧,几乎所有,我的统计是不准确的)浮点数都是不精确的。@High,double比float多29位精度。这使它们的精确度提高了约1亿倍。@Marcelo--确实如此。而且,我们中的许多人在进行严肃的数字运算时,不得不担心长时间运行的计算会导致精度下降。将浮动更改为双倍只会推迟问题,而不会消除问题。当然,有时它会将问题推迟到计算完成之后。是的,但是将mePtr和bPtr转换为double,我仍然可以使用mePtr++吗?或者这将只使用数组中一半的元素吗?b、 数据是float[],如果mePtr是指向b.data[0]的双指针,那么mePtr++的右边不是8个字节,而是b.data[2]而不是b.data[