C# 中的浮点数和双精度
矩阵乘法代码有点问题。 我似乎在大矩阵乘法上失去了精度(我的代码在小矩阵上运行良好)。
我的循环如下:
for (int j = 0; j < columns; j++)
{
float[] column = otherMatrix.Column(j);
for (int i = 0; i < rows; i++)
{
double s = 0;
for (int k = 0; k < size; k++)
s += this[i,k] * ((double) column[k]);
result[i, j] = (float)s;
}
}
如您所见,我强制使用(双)精度以确保在将两个浮点数相乘时不会丢失精度。
查看 IL 代码,我可以看到两个 conv.r8,这让我认为 IL 代码中有这种浮点到双精度的转换。
当运行它并查看反汇编(x86 机器)时,我看到以下内容:
0000024e fld dword ptr [edx+eax*4+8]
00000252 fmulp st(1),st
00000254 fadd qword ptr [ebp-64h]
00000257 fstp qword ptr [ebp-20h]
然而, 乘法,给我我一直在跟踪的错误。
我说得对吗? 有什么办法强制这种双精度乘法吗?
谢谢
Having a bit of a problem here on a matrix multiplication code.
I seem to lose precision on large matrices multiplications (my code runs fine on small matrices).
My loop is the following :
for (int j = 0; j < columns; j++)
{
float[] column = otherMatrix.Column(j);
for (int i = 0; i < rows; i++)
{
double s = 0;
for (int k = 0; k < size; k++)
s += this[i,k] * ((double) column[k]);
result[i, j] = (float)s;
}
}
As you can see, I force a (double) precision to make sure I don't lose precision when multiplying my two floats.
Looking at IL code, I can see two conv.r8 which make me think that IL code has this float-to-double precision conversion in it.
However, when running it and having a look at the disassembly (x86 machine), I see the following :
0000024e fld dword ptr [edx+eax*4+8]
00000252 fmulp st(1),st
00000254 fadd qword ptr [ebp-64h]
00000257 fstp qword ptr [ebp-20h]
It makes me think that JIT has thought that since I'm already multiplying floats, it shouldn't use double precision multiplication but single precision multiplication, giving me the errors I've been tracking.
Am I right ?
Is there any way to force this double precision multiplication ?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为你误解了大会。我相信 FMULP 始终在 80 位寄存器上运行。如果 JIT 在这里做错事,我会感到惊讶。
我建议您使用我的
DoubleConverter
写出算术前后的精确值。这样您应该可以更好地了解正在发生的事情。I think you're misinterpreting the assembly. I believe that FMULP always operates on the 80-bit registers. I would be surprised to see the JIT doing the wrong thing here.
I suggest you use my
DoubleConverter
to write out the precise values before and after the arithmetic. That way you should get a better idea of what's going on.您可能想切换到十进制以获得更好的精度
You might want to switch to decimal for better precision
首先,有什么原因不能使用十进制吗?小数保持任何数字所需的精度,并且不存在浮点数所具有的烦人的“尾数的最接近的二进制表示”问题,该问题可能导致 xy = z +- .0000000000...0000001 错误。
来自 MSDN:
如果做不到这一点,请尝试在相乘之前将两边都转换为两倍。 float * double 可能会产生双精度数,但由于您的双精度数是与另一个浮点数进行比较的变相浮点数,因此编译器可能会忽略您所需的精度,“知道”两个浮点数不会产生双精度数。
First, is there any reason you can't use decimal? Decimals maintain the necessary precision of any number, and don't have the annoying "nearest binary representation of the mantissa" problems floats have that can result in x-y = z +- .0000000000...0000001 errors.
From MSDN:
Failing this, try casting both sides to double before multiplying. float * double may result in a double, but as your double is a float in disguise being compared to another float, the compiler may be ignoring your desired precision, "knowing" that two floats won't make a double.