C#加法问题

sytu_hzj 2010-01-11 12:15:11


float value = 1.9F;
value *= 10;
int temp = (int)(value + 700);





double value = 1.9F;
int temp = (int)(value * 10 + 700);



请高手指教一下,上面两段代码,temp的结果为什么不一样,前者为719,后者为718
...全文
295 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
shighui 2010-01-12
  • 打赏
  • 举报
回复
呵呵,计算机不是万能的。有错。每一个计算都是错的。
c282174871c 2010-01-12
  • 打赏
  • 举报
回复
up
wartim 2010-01-12
  • 打赏
  • 举报
回复
从源头上避免误差

double value2 = double.Parse(1.9F.ToString());
int temp2 = (int)(value2 * 10 + 700);
tiandiyouwo1 2010-01-12
  • 打赏
  • 举报
回复
up
baojian0418 2010-01-12
  • 打赏
  • 举报
回复
强制转化后,不是小数点后面的都舍了吗?不会四舍五入啊?疑惑……
满衣兄 2010-01-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 yfqvip 的回复:]
value * 10 自动转换为int型得18
[/Quote]
说错了,这个时候是不转换的,(int)的时候转换的
twistmost 2010-01-11
  • 打赏
  • 举报
回复
1.9不是一个能无损表示的浮点数。double 有52个有效位,1.9F * 10 有效位可以表示为1 .0010111111111111111111111100000000000000000000000000

但是float只有23有效位,1.9F * 10 有效位必须截断进位表示为 1 .00110000000000000000000。
二者的指数位都是 ×16,所以 float结果反而达到了19
hhc123 2010-01-11
  • 打赏
  • 举报
回复

float 是单精度的
double是双精度的
你断点一下就知道了
满衣兄 2010-01-11
  • 打赏
  • 举报
回复
应该比较好理解,double的精度范围±5.0 × 10^-324 到 ±1.7 × 10^308
当声明double value = 1.9F;时候,其实value的值是1.89999999...这个通过调试可以看到
知道这个下面就好理解了value * 10 自动转换为int型得18
huangheguyun 2010-01-11
  • 打赏
  • 举报
回复
这是精度问题。float和double的问题,高低位转换时会丢失精度的。
ke5315309 2010-01-11
  • 打赏
  • 举报
回复
高位转低位要丢失精度...
sytu_hzj 2010-01-11
  • 打赏
  • 举报
回复
注明一下,这不是double型和float型的区别,因为用float型的也一样。
szyjp 2010-01-11
  • 打赏
  • 举报
回复
真奇怪,不应该啊
tianliang1 2010-01-11
  • 打赏
  • 举报
回复
这是精度问题。float和double的问题。。。
我在地球 2010-01-11
  • 打赏
  • 举报
回复
你说这是为什么,为什么?
苏飞论坛 2010-01-11
  • 打赏
  • 举报
回复
double 这个类型的问题,你可以在网上找找有解决方案
tyy283 2010-01-11
  • 打赏
  • 举报
回复
不太清楚,呵!
HELLOWORDC 2010-01-11
  • 打赏
  • 举报
回复
楼上说的有板有眼,显然是正解。这里面涉及到数据存储和强制转换两个非常非常细节的问题,个人觉得过多地关注这类非常非常细节的问题大可不必,进了“求甚解”的误区。
cuike519 2010-01-11
  • 打赏
  • 举报
回复
首先我要说的是,这确实是一个精度的问题,但是这不是double和float之间的问题(就这个问题而言)。

其次即使你把上面代码中的double换成float效果是一样的,你用一个宽的表示一个窄的这不会有问题的,理论上来说精度更高了。

最后分析一下这个问题,先说说他们生成的IL代码,差异只有一句话就是在求值以后将值赋给value然后再压入求值栈求值,有兴趣的可以看看他们的代码之间的差异,这里我不描述了。下面我从汇编角度来分析一下为什么会是这种结果(其实求值栈的问题我也没想明白,为什么看着只是取出来又放回去就不一样了呢?)。

下面是这两段代码的汇编指令:

0000003a mov dword ptr [ebp-40h],3FF33333h ; 将1.9F保存在栈上的局部变量里面
00000041 fld dword ptr [ebp-40h] ; 将1.9F装入浮点寄存器ST0
00000044 fmul dword ptr ds:[0050156Ch] ; 将浮点寄存器ST0里面的乘以10保存到ST0里面
0000004a sub esp,8 ; 调整栈指针
0000004d fstp qword ptr [esp] ; 将ST0里面的值放到栈顶作为调用716E133C的参数
00000050 call 716E133C ; 调用转换函数
============================================================================
0000003a mov dword ptr [ebp-40h],3FF33333h ; 将1.9F保存在栈上的局部变量里面
00000041 fld dword ptr ds:[00571570h] ; 将1.9F装入浮点寄存器ST0
00000047 fmul dword ptr [ebp-40h] ; ST0*ebp-40h保存到ST0里面
0000004a fstp dword ptr [ebp-40h] ; 将ST0的值保存在ebp-40的位置
0000004d fld dword ptr [ebp-40h] ; 将这个ebp-40h上的浮点取出来放到ST0里面
00000050 sub esp,8 ; 调整栈指针
00000053 fstp qword ptr [esp] ; 将ST0里面的值放到栈顶作为调用7167133C的参数
00000056 call 7167133C ; 调用转换函数

可以看出问题就在红色的这两句(貌似和IL是一致的),实际上float在浮点寄存器的里面的值是: +1.8999999761581420e+0001,但是当保存到栈上再取出来以后就变成了+1.9000000000000000e+0001,这里存在一个“隐式转换”。

显然正确的结果应该是19而不是18,通过上面的分析,程序稍加修改便可以得到正确的输出结果:
int temp = (int)((float)(value2 * 10 + 700));
再转整形之前将求值内容转换成float即可。


个人意见,仅供参考。
Valefish 2010-01-11
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 tianliang1 的回复:]
这是精度问题。float和double的问题。。。
[/Quote]

好好 单步调试下吧 看看有每个值什么区别
加载更多回复(13)

111,123

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧