Lazarus中文社区

 找回密码
 立即注册(注册审核可向QQ群索取)

QQ登录

只需一步,快速开始

Lazarus IDE and 组件 下载地址版权申明
查看: 6643|回复: 12

我编了个小程序,laz和delphi编译出来速度运行速度差很多,大家帮看看

[复制链接]

该用户从未签到

发表于 2015-3-23 17:26:36 | 显示全部楼层 |阅读模式
就是下面这段,根据一些给出的数,算出另一个数,如果delphi执行要1秒的话,laz要2秒,我觉得这差的太多了
我电脑配置:intel E3400@2G,sdd 硬盘
不知道是不是我的电脑配置低了呢,
另外,还有个问题,就是下面程序里计算部分的这两句
        res := (n*h);
        res := res * 1000000;
必须分开写才行,如果写在一起,
      res := (n*h*1000000);
得到的结果就是错的,laz得到的结果少,而delphi一个结果也得不到,这是为什么呢
附件里是两个工程,分别用delphi2007和laz最新的1.4编译
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
h :Word;
m : Word;
n :Word;
r : Word;
d : Word;
o : Word;
t_str : AnsiString;
res : Currency;
v_start : Currency;
v_end : Currency;
begin
  //dis_fs_f;
  Form1.speedbutton1.Enabled := False;
  h := StrToInt(Form1.Edit1.Text); //h = 12
  v_start := StrToFloat(Form1.Edit3.Text);  //v_start = 44090
  v_end := StrToFloat(Form1.Edit4.Text);//v_end = 44110
  for m:= StrToInt(Form1.Edit2.Text) to h do //m = 12
  for n := 2 to 432 do
    begin
    for r := 2 to 7 do
      begin
      for d := 2 to 255 do
        begin
        for o := 0 to 1 do
        begin
        //t_str := 'H=' + IntToStr(h) + '; ';

        res := (n*h);
        res := res * 1000000;
        //res := h/m;
        res := res /(m*r);
        //res := res/r;
        if Form1.CheckBox1.Checked then
          res := res/(256*(2*d + o))
        else
          res := res/(32*(2*d + o));
        if Form1.RadioButton2.Checked then
          res := res/(2*(2*d + o));
        //res := res/(2*d + o);
        if (res >= v_start) and (res <= v_end) then
        begin
                t_str :='M=' + IntToStr(m) + '; ';
        t_str :=t_str + 'N=' + IntToStr(n) + '; ';
        t_str :=t_str + 'R=' + IntToStr(r) + '; ';
        t_str :=t_str + 'DIV=' + IntToStr(d) + '; ';
        t_str :=t_str + 'ODD=' + IntToStr(o) + '; ';
          t_str := t_str + FloatToStrF(res,ffNumber,11,5);
        Memo1.Lines.Add(t_str);
        end;
        end;
        end;
      end;
    end;

    form1.speedbutton1.Enabled := True;
end;   

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册(注册审核可向QQ群索取)

x
回复

使用道具 举报

该用户从未签到

发表于 2015-3-24 09:10:11 | 显示全部楼层
本帖最后由 chenyuchih 于 2015-3-24 09:58 编辑

關於執行結果正確性的部分,根據小弟測試,應該是整數資料型態溢位(overflow)所造成的:

例1
當n = 271, h=12時,
res := (n*h);  //Word*Word乘出來的結果是3252(還在Word有效的範圍內),算完才將之轉存為Currency type
res := res * 1000000; //Currency type乘完得到3252000000,還在Currency有效的範圍內 → 故結果正確
但是如果寫在一起 res := (n*h*1000000); //Word*Word*1000000直接得到3252000000,此時已經超過Word有效範圍,因溢位發生所以其值已不正確,故轉存Currency type仍為錯誤的內容
此例把 n 與 h 都宣告成 DWord type (32bit 不帶正負號整數) 會有幫助。

例2
當n = 429, h=12時,
res := (n*h);  //Word*Word乘出來的結果是5148(還在Word有效的範圍內),算完才將之轉存為Currency type
res := res * 1000000; //Currency type乘完得到5148000000,還在Currency有效的範圍內 → 故結果正確
但是如果寫在一起 res := (n*h*1000000); //Word*Word*1000000直接得到5148000000,此時已經超過Word有效範圍,因溢位發生所以其值已不正確,故轉存Currency type仍為錯誤的內容
因5148000000也超過DWord的有效範圍,所以就算此例把 n 與 h 都宣告成 DWord 也沒有用

所以,根本解決之道就是如樓主的做法:要乘大數或是有可能乘完的結果超出原資料型態範圍時,先轉到較大範圍的資料型態後再乘,或是一律用該種類最大範圍的型態 (整數用int64 / 浮點數用 Double或Extended)

另外性能的問題小弟就不知道該如何解釋或處理了.....以上所述若有誤,還希望版上前輩出面指點一二,讓小弟也能學習一下,謝謝!
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-3-24 10:51:34 | 显示全部楼层
chenyuchih 发表于 2015-3-24 09:10
關於執行結果正確性的部分,根據小弟測試,應該是整數資料型態溢位(overflow)所造成的:

例1

太感谢了!!!加了两个中间变量
        t_h :  Currency;
        t_n: Currency;
然后
        t_h := h;
        t_n := n;
        res := (t_n*t_h*1000000);
就可以了。
我一直以为编译器是会自动类型转换的,就是先把n,h转成res一样的类型,然后才计算的。
不过为什么原来那么写laz可以算出来一些结果,而delphi一个也算不出呢,搞不懂啊
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-3-24 11:20:21 | 显示全部楼层
我想是不是这样的,从现在的“现象”来看:
  对于  res := (n*h*1000000);
在laz里面,n,h都是word,但是结果超范围了,它把结果转为了dword,然后赋给res,所以只有后面那个很大的数得不到结果
在delphi里,结果超范围了,它没做任何处理,所以一个结果也得不到
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2015-3-24 11:36:43 | 显示全部楼层
forgetall 发表于 2015-3-24 11:20
我想是不是这样的,从现在的“现象”来看:
  对于  res := (n*h*1000000);
在laz里面,n,h都是word,但是 ...

其實FPC有個檢查overflow的開關,只是預設是off的,若是在單元內加上指令

{$OVERFLOWCHECKS ON}

那運行到溢位發生時就會跳出Exception讓你知道。

至於delphi....我已經沒接觸很久了,所以不太清楚 ^^"
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-3-24 16:51:37 | 显示全部楼层
chenyuchih 发表于 2015-3-24 11:36
其實FPC有個檢查overflow的開關,只是預設是off的,若是在單元內加上指令

{$OVERFLOWCHECKS ON}

谢谢,试了一下,确实可以的。
另外我想,laz并没有自动转换数据类型,而是编译的时候把word当dword处理的,都是4字节。
而delphi中word是2字节,dword是4字节。
不过我不知道怎么测试呢
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2015-3-31 01:33:03 | 显示全部楼层
本帖最后由 bttt 于 2015-3-31 01:40 编辑

没有安装delphi,分析了一下fpc的汇编,觉得问题在这两个地方:
  1. if Form1.CheckBox1.Checked then
  2. if Form1.RadioButton2.Checked then
复制代码
在每次循环里都重新算了一次。据此,增加两个布尔变量
  1.   c1:=    Form1.CheckBox1.Checked  ;
  2.   r2:=   Form1.RadioButton2.Checked;   
复制代码
在循环里面改成用这两个,速度就快了。

但是这样好像也不太符合原意,如果有其他线程改了这两个值呢?一般来说当代处理器通常会预先尝试分支……不行,编不下去了……

不管咋说这里也可以看出fpc的优化太弱了……
回复 支持 反对

使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-15 09:19
  • 签到天数: 9 天

    [LV.3]偶尔看看II

    发表于 2015-3-31 23:54:04 | 显示全部楼层
    bttt 发表于 2015-3-31 01:33
    没有安装delphi,分析了一下fpc的汇编,觉得问题在这两个地方:在每次循环里都重新算了一次。据此,增加两个 ...


    对状态的判断可以这样子的
    if CheckBox1.State=cbChecked then //选中
    if CheckBox1.State=cbUnchecked then//未选中
    我挨它坑过····
    回复 支持 反对

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2015-4-1 20:30:07 | 显示全部楼层
    本帖最后由 forgetall 于 2015-4-1 20:33 编辑
    bttt 发表于 2015-3-31 01:33
    没有安装delphi,分析了一下fpc的汇编,觉得问题在这两个地方:在每次循环里都重新算了一次。据此,增加两个 ...

    我擦!!!
    我试了一下,吓尿了,速度刷刷的,和delph一样快...
    本菜鸟表示很不理解呀
    回复 支持 反对

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2015-4-1 20:44:52 | 显示全部楼层
    gucao 发表于 2015-3-31 23:54
    对状态的判断可以这样子的
    if CheckBox1.State=cbChecked then //选中
    if CheckBox1.State=cbUncheck ...

    晕,我一直都不知道有这么个state...
    回复 支持 反对

    使用道具 举报

    *滑块验证:

    本版积分规则

    QQ|手机版|小黑屋|Lazarus中国|Lazarus中文社区 ( 鄂ICP备16006501号-1 )

    GMT+8, 2025-5-2 21:40 , Processed in 0.035731 second(s), 9 queries , Redis On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表