procedure TForm1.Button1Click(Sender: TObject);
var f:real ;
begin
  f:=14.85 ;
  showmessage(inttostr(trunc(f*10+0.5))) ; //结果: 148
  showmessage(inttostr(trunc(14.85*10+0.5))) ;  //结果: 149
end;为什么结果不一样呢?好奇怪!

解决方案 »

  1.   

    f*10 = real
    14.85*10 = float數據類型不同, 我估計是這樣的
      

  2.   

    我们是这样想的,首先real型的f在存储14.85由于二进制的关系肯定是存的一个近似值,在这里可能就是一个小于14.85的近似值. 于是f*10+0.5就对应着一个小于149的近似值. trunc然后去掉148.999...后的近似部分发,变成了148
    更多的我就不知了
    建议如有可能的话多用ROUND
      

  3.   

    我觉得单纯用你那一种类型还得不出什么结论,我还没来得及总结,但我改写的过程可以了解到更多的东西,另外建议用CPU window找到变量实际存储的位置看一下具体是怎么回事
    var
      e:Extended  ;
      r:real;
      s:single;
    begin
      s:=14.85 ;
      r:=14.85 ;
      e:=14.85 ;
      showmessage(inttostr(trunc(s*10+0.5))) ; //结果: 149
      showmessage(inttostr(trunc(r*10+0.5))) ; //结果: 148
      showmessage(inttostr(trunc(e*10+0.5))) ; //结果: 149
      showmessage(inttostr(trunc(14.85*10+0.5))) ;  //结果: 149
    end;
      

  4.   

    看来trunc对real数据处理有问题
    我同事有时好象用floor和ceil也有一些问题
      

  5.   

    bcrun(网狐(bbs.bcrun.com)) 兄弟说的有道理,应该是近似值的缘故,我通过下面的例子可以充分说明这一点:procedure TForm1.Button2Click(Sender: TObject);
    var f:real ;
    begin
       f:=14.85 ;
       showmessage(floattostr(frac(f*10))) ;  //结果是0.499999999999996 而不是0.5
    end;这样一来,岂不是大家的四舍五入的函数就不很精确了?比如输入14.85,要求精确到角,就会出问题?!
      

  6.   

    bcrun(网狐(bbs.bcrun.com)) 兄弟说的有道理。不过误差范围很小,你可以加上个0.000001。
    我以前也遇见过类似的问题,判断浮点数是否相等,直接用A=B是有问题的,后来一直这样判断:
    if Abs(A - B) < 0.000001 then
    ...四舍五入最邪门的我记得有一个数字:16.025,Round后总给我舍成16.02,后来没办法,自己来处理的
      

  7.   

    Delphi Pascal 编译器中,Round 函数是以 CPU 的 FPU (浮点部件) 处理器为基础的。这种处理器采用了所谓的 "银行家舍入法",即对中间值 (如 5.5、6.5) 实施Round函数时,处理器根据小数点前数字的奇、偶性来确定舍入与否,如 5.5 Round 结果为 6,而 6.5 Round 结果也为6, 因为 6 是偶数。
      

  8.   

    货币类型应该定义为Currency比较好
      

  9.   

    我增加了一些查看中间处理的方法,我的大致结论是,前述推测f中存储了小于14.85的近似值应该没错,而其后又因为TRUNC函数接受的参数是Extended类型的,转换到这个类型后参数变成了一个小于149的近似值了. 这里关键是通过CPU WINDOW看实际在运算中传递的值. 单双精度数的存储方式可参看这篇文章(里面有处错误,把32位单精度二进制数写成64位了)
    http://www.ddvip.net/program/c++/base/94.htm
    我分析时用的过程:
    var
      e,e1:Extended  ;
      r,r2:real;     //real = double
      s:single;
    begin
      s:=14.85 ;
    //  s:=34.526 ;
      r:=14.85 ;
      e:=14.85 ;
      r2:= r*10+0.5;
      e1:= r*10+0.5;      //trunc(e1)后变为148
      //此时从CPU窗口看到实际的8个字节是00 FF FF FF FF FF FF 94
      showmessage(inttostr(trunc(e1))) ; //结果: 与前面的赋值方式有关
      //showmessage(floattostr(e1));
      e1:= 149;         //trunc(e1)后变为149
      //此时从CPU窗口看到实际的8个字节是00 00 00 00 00 00 00 95
      showmessage(inttostr(trunc(e1))) ; //结果: 与前面的赋值方式有关
      showmessage(inttostr(trunc(r2))) ; //结果: 149
      showmessage('变量r:real的字节数: ' + inttostr(Sizeof(r))) ; //结果: 8
      showmessage(inttostr(trunc(s*10+0.5))) ; //结果: 149
      showmessage(inttostr(trunc(r*10+0.5))) ; //结果: 148  //这一行的REAL转换不知为什么不能编译
      //showmessage(inttostr(trunc(Real(r*10+0.5)))) ; //结果:
      showmessage(inttostr(trunc(e*10+0.5))) ; //结果: 149
      showmessage(inttostr(trunc(14.85*10+0.5))) ;  //结果: 149
    end;
      

  10.   

    补充:
    感觉好像是在DELPHI中做浮点运算时,一开始会默认把数转为更精确的EXTENDED类型进行运算,这就解释了两点:
    一,trunc(14.85*10+0.5)一开始就把数转换成了高精度的Extended类型计算(如选Optimization编译时大概是编译时就已经算出最后值149写到EXE文件中去的,不过我分别在Optimization选与不选两种状态上测试过上过程,弹出的消息框中看到的结果都是一样的),所以计算准确. 
    trunc(r*10+0.5)中由于指明是real类型所以不同
    二,我那一句//showmessage(inttostr(trunc(Real(r*10+0.5)))) ; //结果:
    不能编译是因为r*10+0.5的结果是高精度的Extended类型的,不能向低精度类型强行转换,
    我改成showmessage(inttostr(trunc(Extended(r*10+0.5))))后是可以编译的