Recent

Author Topic: Lazarus cannot handle simple calculations?  (Read 11841 times)

Waco

  • Jr. Member
  • **
  • Posts: 61
Lazarus cannot handle simple calculations?
« on: August 26, 2009, 12:52:16 pm »
I've got an odd problem and it had taken me quite a while till I sorted it out. I didn't want to believe my eyes, so I made several screenshots. I really doubt that I have something wrong there.
(http://img194.imageshack.us/img194/9339/scr1t.th.jpg)
(http://img194.imageshack.us/img194/8454/scr2p.th.jpg)
(http://img405.imageshack.us/img405/6329/scr3.th.jpg)
(http://img151.imageshack.us/img151/3222/scr4c.th.jpg)

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1933
Re: Lazarus cannot handle simple calculations?
« Reply #1 on: August 26, 2009, 01:50:32 pm »
Gosh, do we really have to look at 4 screenshots for this little problem?

var n1,m1,m2:integer;
e:double;
begin
{$Q+}
n1:=78;
m1:=295;
m2:=162;
e:=8*n1*n1*m1*m2;
end;

Arithmetic Overflow, the double "e" can't hold the resulting value.
using {$Q+} you get an error message.

Vincent Snijders

  • Administrator
  • Hero Member
  • *
  • Posts: 2661
    • My Lazarus wiki user page
Re: Lazarus cannot handle simple calculations?
« Reply #2 on: August 26, 2009, 01:52:00 pm »
If you cannot believe it, compile with overflow and range checking.

The value is too big to fit in an integer, either use int64 or convert to floating point (double) before calculation.

Waco

  • Jr. Member
  • **
  • Posts: 61
Re: Lazarus cannot handle simple calculations?
« Reply #3 on: August 26, 2009, 02:02:30 pm »
Alright, it seems that yet again, I've made a mistake... But I don't get it, double is supposed to have range up to 1.79 x 10^308, so why should 'e' overflow? I deliberately used double to avoid any overflows. Vincent, so how do I convert to floating point?

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1933
Re: Lazarus cannot handle simple calculations?
« Reply #4 on: August 26, 2009, 03:55:12 pm »
I think the problem is not with the resulting "double" but it's an integer overflow.

Try this  (should work):
Code: [Select]
var n1,m1,m2:cardinal; //instead of integer, double might work too.
e:double;
begin
{$Q+}
n1:=78;
m1:=295;
m2:=162;
e:=8*n1*n1*m1*m2;
caption:=floatToStr(e);
end;

Ask the compiler developers for details:
http://www.freepascal.org/maillist.var see fpc-pascal
« Last Edit: August 26, 2009, 03:57:37 pm by theo »

Vincent Snijders

  • Administrator
  • Hero Member
  • *
  • Posts: 2661
    • My Lazarus wiki user page
Re: Lazarus cannot handle simple calculations?
« Reply #5 on: August 26, 2009, 04:03:09 pm »
using cardinal instead of integer only doubles the range.

try:
Code: [Select]
e := 8*(n1*(n1*(m1*int64(m2)));then the multiplication is evaluated using 64 bit integers.


skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Lazarus cannot handle simple calculations?
« Reply #6 on: August 26, 2009, 04:03:24 pm »
how about?

e:=8*double(n1)*double(n1)*double(m1)*double(m2);

Vincent Snijders

  • Administrator
  • Hero Member
  • *
  • Posts: 2661
    • My Lazarus wiki user page
Re: Lazarus cannot handle simple calculations?
« Reply #7 on: August 26, 2009, 04:10:13 pm »
That is the conversion to double alternative, I mentioned.

Waco

  • Jr. Member
  • **
  • Posts: 61
Re: Lazarus cannot handle simple calculations?
« Reply #8 on: August 26, 2009, 07:37:27 pm »
I see... Thanks for clearing things out, but wouldn't it be logical, if the multiplication is evaluated using the type of variable, which is being calculated?

Vincent Snijders

  • Administrator
  • Hero Member
  • *
  • Posts: 2661
    • My Lazarus wiki user page
Re: Lazarus cannot handle simple calculations?
« Reply #9 on: August 26, 2009, 08:41:27 pm »
wouldn't it be logical, if the multiplication is evaluated using the type of variable, which is being calculated?
Maybe more logical for you, but that is not how it is done in Pascal. The value of an expression is determined by the expression and is not influenced by what you do with the expression.

Waco

  • Jr. Member
  • **
  • Posts: 61
Re: Lazarus cannot handle simple calculations?
« Reply #10 on: August 26, 2009, 09:24:31 pm »
Well, I think it would be more logical generally, but whatever. Anyway, thanks for your assistance, I "somehow" get it know.

sasa

  • Guest
Re: Lazarus cannot handle simple calculations?
« Reply #11 on: August 27, 2009, 07:40:11 am »
In addition to other posts. In FPC, resulting mid-calculation variable do not relyes on resulting variable type as in Delphi. Type of variable is upgrading during calculation process, depending on each operand type. When calculation is finished, result is converted to resulting variable type. This way is probably done to speedup the whole calculation process.

At end, to ensure non-overflowing in this case:

e:=double(1.0)*...

Vincent Snijders

  • Administrator
  • Hero Member
  • *
  • Posts: 2661
    • My Lazarus wiki user page
Re: Lazarus cannot handle simple calculations?
« Reply #12 on: August 27, 2009, 07:48:31 am »
At end, to ensure non-overflowing in this case:

e:=double(1.0)*...
This is not safe, because then you are relying on the order in which the expression is evaluated. If it is evaluated from right to left (which the compiler is allowed to do, and this is even documented), you end up with the same overflow.

That is the reason I added so many braces in the int64 example.

sasa

  • Guest
Re: Lazarus cannot handle simple calculations?
« Reply #13 on: August 27, 2009, 08:15:46 am »
This is not safe, because then you are relying on the order in which the expression is evaluated.

You have a point, hopefully compiler currently work left to right way regarding each sub-expression.

Anyway, your code will overflow as well when exceed int64 range.

Worst, for my own expression evaluator project I made clearing brackets after parsing if operation priority is the same, to speedup calculation (users 3D functions drawing), so in the future compiler releases may fail that as well...

As I wrote explanation, currently, in this case:
e:=8*n1*n1*m1*m2;

it is enough:
e:=double(1.0)*8*n1*n1*m1*m2;

If there is many sub-expressions (operation priority change), each will start regarding its own operand type and thus will lead to overflow.

I.e, this will overflow as well:
e:=double(1.0)*8*n1*n1*m1*m2+
8*n1*n1*m1*m2;

This will pass:
e:=double(1.0)*8*n1*n1*m1*m2+
double(1.0)*8*n1*n1*m1*m2;

After I looked at pictures provided by OP, I would suggest to change all function parameter types as well as in function variables to resulting one, regarding calculation complexity ...

I'm not sure there is a compiler directive about this (to get a resulting variable type for each subcalculation instead), but behavior with Delphi mode switch gives the same result as in FPC mode. This is definitely problematic, even if intention to speedup the calculation may have been the goal.
« Last Edit: August 27, 2009, 08:52:15 am by sasa »

Vincent Snijders

  • Administrator
  • Hero Member
  • *
  • Posts: 2661
    • My Lazarus wiki user page
Re: Lazarus cannot handle simple calculations?
« Reply #14 on: August 27, 2009, 08:52:15 am »
I think the fpc docs are clear: read the remark on http://www.freepascal.org/docs-html/ref/refch9.html


 

TinyPortal © 2005-2018