是因为精度丢失引起的。 根本原因是计算机是按照二进制来存储和处理数据的,有些小数变成二进制表示时会无限长,无法精确表示,所以就存在精度丢失的问题。int c = (int)(a * b); //结果0 可以等效成: var j = (int) ((double) (a*b)); 由于b你强制指定是float,这时候相当于将doubl转成float,会有精度丢失的可能。接着你(a*b)其实暗含将float转会double,因为之前已经有精度问题,所以这里数据已经不对,结果为0就可以解释了。 你可以试一试: float b = 0.01f; var i = (double)b; 看看此时的i是不是和原来的0.01不一样了。然后再看会那个等效的语句。 int cc=(int)(100*0.01); 结果1 因为C#里0.01就是double型(默认小数是这个数据类型),不存在float和double转换时精度丢失的问题。
强制类型转换直接忽略尾数,所以当结果略小的时候,就会差1。而convert转换是四舍五入的。
结论,不要用强制类型转换。
float b = 0.01f;
int c = (int)(a * b);//结果0
00972993 fild dword ptr [ebp-40h] 32位浮点压栈
00972996 fstp dword ptr [ebp-94h] 32位浮点出栈 比double多出这一步
0097299C fld dword ptr [ebp-94h] 再传入寄存器 比double多出这一步,说明是先将float要先转化成double再转化成int,根本原因就是这里 的转化出现了误差
009729A2 fmul dword ptr [ebp-44h] 乘法
009729A5 fstp qword ptr [ebp-9Ch] 弹出 64位浮点
009729AB movsd xmm0,mmword ptr [ebp-9Ch] 将上面64位浮点传参
009729B3 cvttsd2si eax,xmm0 强转浮点
009729B7 mov dword ptr [ebp-48h],eax int ccc = Convert.ToInt32(a * b);//结果1
009729C1 fild dword ptr [ebp-40h]
009729C4 fstp dword ptr [ebp-94h]
009729CA fld dword ptr [ebp-94h]
009729D0 fmul dword ptr [ebp-44h]
009729D3 sub esp,4
009729D6 fstp dword ptr [esp]
009729D9 call 731167DC 关键这行调用了一个函数处理转化
009729DE mov dword ptr [ebp-78h],eax
009729E1 mov eax,dword ptr [ebp-78h]
009729E4 mov dword ptr [ebp-50h],eax
int cc = (int)(100 * 0.01); // 这里的0.01默认是double类型
009729F0 fild dword ptr [ebp-40h] 这里几乎和float一样只少了32转64的步骤
009729F3 fmul qword ptr [ebp-58h]
009729F6 fstp qword ptr [ebp-9Ch]
009729FC movsd xmm0,mmword ptr [ebp-9Ch]
00972A04 cvttsd2si eax,xmm0
00972A08 mov dword ptr [ebp-5Ch],eax
根本原因是计算机是按照二进制来存储和处理数据的,有些小数变成二进制表示时会无限长,无法精确表示,所以就存在精度丢失的问题。int c = (int)(a * b); //结果0
可以等效成: var j = (int) ((double) (a*b));
由于b你强制指定是float,这时候相当于将doubl转成float,会有精度丢失的可能。接着你(a*b)其实暗含将float转会double,因为之前已经有精度问题,所以这里数据已经不对,结果为0就可以解释了。
你可以试一试:
float b = 0.01f;
var i = (double)b;
看看此时的i是不是和原来的0.01不一样了。然后再看会那个等效的语句。
int cc=(int)(100*0.01); 结果1
因为C#里0.01就是double型(默认小数是这个数据类型),不存在float和double转换时精度丢失的问题。
我运行的结果c就是1。