关于浮点类型精度的问题? ( 积分: 50 )

  • 主题发起人 主题发起人 dywapple
  • 开始时间 开始时间
D

dywapple

Unregistered / Unconfirmed
GUEST, unregistred user!
我使用TClientDataSet数据集,在该数据集中添加一个字段a,设为float类型,其精度(pricision,即小数点)设置为2。<br>&nbsp;&nbsp;&nbsp;&nbsp;在程序运行时,在该字段里输入0.5678之类的数据,则会四舍五入为0.57,这是正确的,但是我若输入1.5678,则会四舍五入为1.6,这是错误的,正确应该为1.57。这都是数据集自动完成的,无法手工控制。<br>&nbsp;&nbsp;&nbsp;&nbsp;想问问有没有遇到过类似情况的朋友,该怎么解决它?
 
没人顶我自己顶
 
要让更多的人看到这个帖子。
 
有人遇到类似的情况吗?
 
没遇到过,建议你多试几个数,看看有什么规律先
 
找到了一点规律,即输入的数如果小于1,如0.556,,四舍五入得到的结果正确,如果大于1,如1.556,四舍五入就变成了1.6,我之前设定是保留两位小数的。
 
将ADOQUERY的ENABLEDBCD设为FALSE
 
这是浮点数的问题,微软的开发工具就没有这个问题,delphi就有这个问题,用curreny数据类型试试
 
delphi就是有这个问题
 
有其他的解决办法吗?
 
Delphi的四舍五入函数Round有BUG,无法正常工作。<br>&nbsp;&nbsp;&nbsp;&nbsp;对于XXX.5的情况,整数部分是奇数,那么会Round&nbsp;Up,偶数会Round&nbsp;Down,例如:<br>&nbsp;&nbsp;&nbsp;&nbsp;x:=&nbsp;Round(17.5)&nbsp;=&nbsp;x&nbsp;=&nbsp;18<br>&nbsp;&nbsp;&nbsp;&nbsp;x:=&nbsp;Round(12.5)&nbsp;=&nbsp;x&nbsp;=&nbsp;12<br>&nbsp;&nbsp;&nbsp;&nbsp;请使用下面的函数代替Round:<br>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;DoRound(Value:&nbsp;Extended):&nbsp;Int64;<br>&nbsp;&nbsp;&nbsp;&nbsp;procedure&nbsp;Set8087CW(NewCW:&nbsp;Word);<br>&nbsp;&nbsp;&nbsp;&nbsp;asm<br>&nbsp;&nbsp;&nbsp;&nbsp;MOV&nbsp;Default8087CW,AX<br>&nbsp;&nbsp;&nbsp;&nbsp;FNCLEX<br>&nbsp;&nbsp;&nbsp;&nbsp;FLDCW&nbsp;Default8087CW<br>&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;const<br>&nbsp;&nbsp;&nbsp;&nbsp;RoundUpCW&nbsp;=&nbsp;$1B32;<br>&nbsp;&nbsp;&nbsp;&nbsp;var<br>&nbsp;&nbsp;&nbsp;&nbsp;OldCW&nbsp;:&nbsp;Word;<br>&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;OldCW&nbsp;:=&nbsp;Default8087CW;<br>&nbsp;&nbsp;&nbsp;&nbsp;try<br>&nbsp;&nbsp;&nbsp;&nbsp;Set8087CW(RoundUpCW);<br>&nbsp;&nbsp;&nbsp;&nbsp;Result&nbsp;:=&nbsp;Round(Value);<br>&nbsp;&nbsp;&nbsp;&nbsp;finally<br>&nbsp;&nbsp;&nbsp;&nbsp;Set8087CW(OldCW);<br>&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;end;<br><br>请适当修改上面的代码,做成个通用函数,其实问题的主要原因是8087的控制字问题<br>system.pas中有如下两个函数<br>procedure&nbsp;Set8087CW(NewCW:&nbsp;Word);<br>function&nbsp;Get8087CW:&nbsp;Word;
 
谢谢teclick的提醒,borland没有注意到这个bug吗?
 
这不是bug,&quot;在最近版本的Delphi&nbsp;Pascal&nbsp;编译器中,Round&nbsp;函数是以&nbsp;CPU&nbsp;的&nbsp;FPU&nbsp;(浮点部件)&nbsp;处理器为基础的。这种处理器采用了所谓的&nbsp;&quot;银行家舍入法&quot;,即对中间值&nbsp;(如&nbsp;5.5、6.5)&nbsp;实施Round函数时,处理器根据小数点前数字的奇、偶性来确定舍入与否,如&nbsp;5.5&nbsp;Round&nbsp;结果为&nbsp;6,而&nbsp;6.5&nbsp;Round&nbsp;结果也为6,&nbsp;因为&nbsp;6&nbsp;是偶数&quot;。<br><br>Round函数其实使用的银行家算法进行运算的,统计学上一般也是使用这种算法的,这比我们传统的四舍五入方法要科学<br>在math.pas中有下面的方法,也可以实现<br><br>TFPURoundingMode&nbsp;=&nbsp;(rmNearest,&nbsp;rmDown,&nbsp;rmUp,&nbsp;rmTruncate);<br>{&nbsp;Return&nbsp;the&nbsp;current&nbsp;rounding&nbsp;mode&nbsp;}<br>function&nbsp;GetRoundMode:&nbsp;TFPURoundingMode;<br><br>{&nbsp;Set&nbsp;the&nbsp;rounding&nbsp;mode&nbsp;and&nbsp;return&nbsp;the&nbsp;old&nbsp;mode&nbsp;}<br>function&nbsp;SetRoundMode(const&nbsp;RoundMode:&nbsp;TFPURoundingMode):&nbsp;TFPURoundingMode;<br><br>函数也可以这样写<br>function&nbsp;RoundEx(Value:&nbsp;Extended;&nbsp;RoundMode:&nbsp;TFPURoundingMode&nbsp;=&nbsp;rmUp):&nbsp;Int64;<br>var<br>&nbsp;&nbsp;RM:&nbsp;TFPURoundingMode;<br>begin<br>&nbsp;&nbsp;RM&nbsp;:=&nbsp;GetRoundMode;<br>&nbsp;&nbsp;try<br>&nbsp;&nbsp;&nbsp;&nbsp;SetRoundMode(RoundMode);<br>&nbsp;&nbsp;&nbsp;&nbsp;Result&nbsp;:=&nbsp;Round(Value);<br>&nbsp;&nbsp;finally<br>&nbsp;&nbsp;&nbsp;&nbsp;SetRoundMode(RM);<br>&nbsp;&nbsp;end;<br>end;
 
to&nbsp;teclick:<br>&nbsp;&nbsp;&nbsp;&nbsp;为何说银行家算法比常规的四舍五入要好呢?
 
谢谢各位的提醒。
 
5.5=&nbsp;6<br>6.5=&nbsp;6<br>5.5+6.5=12<br>这就是银行家算法的&nbsp;优点。<br>2组数据,四舍五入前后,合计相等。
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
916
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部