Recent

Author Topic: Wrong results with Integer numbers math.  (Read 3602 times)

Apollo286

  • Newbie
  • Posts: 5
Wrong results with Integer numbers math.
« on: January 05, 2021, 11:03:06 pm »
Hi, I wrote simple code an I have two different results on Win10 and Ubuntu. I don't know where is the problem.
Here is my code:

Code: Pascal  [Select][+][-]
  1. ...
  2. var a, b, c, d : longint;
  3.       myResult : Int64;
  4. ...
  5.   a := 828;
  6.   b := 653;
  7.   c := 12362752;
  8.   d := 552;        
  9.  
  10.   myResult := ((a-b)*c) div d;
  11.  
  12.  

Lazarus 2.0.10, in Ubuntu:        myResult = 3919350               
Lazarus 2.0.10, in Windows:     myResult = -3861387

The same code, but two different results. Result in Ubuntu is valid for me. I think - problem is with integer division, but I don't know to fix it.
Please, have somebody any tip or solution for my problem?
Thx.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8540
Re: Wrong results with Integer numbers math.
« Reply #1 on: January 05, 2021, 11:15:50 pm »
You'd help everybody enormously if you said what version of FPC, what processor you were using, and what mode the compiler is running in.

I've spent a chunk of the evening investigating the history of why the mod operator acts oddly so just don't start on that one (yet)... OK? :-)

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

wp

  • Hero Member
  • *****
  • Posts: 13397
Re: Wrong results with Integer numbers math.
« Reply #2 on: January 05, 2021, 11:40:35 pm »
Your calculation in myResult has an integer overflow. Turn on the "I/O overflow" box in the Debugging page of the Project options to get an error message. To fix the problem declare all longint as Int64 (or at least one of the factors in the product term). Or cast a in the myResult calculation to int64:
Code: Pascal  [Select][+][-]
  1. var a, b, c, d : longint;
  2.       myResult : Int64;
  3. ...
  4.   a := 828;
  5.   b := 653;
  6.   c := 12362752;
  7.   d := 552;        
  8.  
  9.   myResult := ((Int64(a)-b)*c) div d;

Apollo286

  • Newbie
  • Posts: 5
Re: Wrong results with Integer numbers math.
« Reply #3 on: January 05, 2021, 11:41:24 pm »
Thank you for answer (and sorry for my english).  :)

processor: AMD A10-7800
fpc version:   Ubuntu 20.04 64bit - fpc-laz 3.2.0
                     Windows 10  64bit - fpc 3.2.0
compiler mode: {$mode objfpc}

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1575
    • Lebeau Software
Re: Wrong results with Integer numbers math.
« Reply #4 on: January 05, 2021, 11:45:41 pm »
Lazarus 2.0.10, in Ubuntu:        myResult = 3919350               

That is the correct result when Longint is 64bits in size.

Lazarus 2.0.10, in Windows:     myResult = -3861387

That is the correct result when Longint is 32bits in size.

The same code, but two different results.

Because you are operating on a data type that has different sizes on different platforms.

I think - problem is with integer division

Actually, the problem is with the integer multiplication.

When Longint is 32bits, the result of ((a-b)*c) (((828-653)*12362752) = 2163481600) overflows the max value of Longint (2147483647), so the result of the multiplication is a negative value (-2131485696), then the result of the integer division is also negative (-2131485696 / 552 = -3861387).

When Longint is 64bits, there is no overflow.
« Last Edit: January 05, 2021, 11:53:48 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Apollo286

  • Newbie
  • Posts: 5
Re: Wrong results with Integer numbers math.
« Reply #5 on: January 06, 2021, 12:06:22 am »
Your calculation in myResult has an integer overflow. Turn on the "I/O overflow" box in the Debugging page of the Project options to get an error message. To fix the problem declare all longint as Int64 (or at least one of the factors in the product term). Or cast a in the myResult calculation to int64:
Code: Pascal  [Select][+][-]
  1. var a, b, c, d : longint;
  2.       myResult : Int64;
  3. ...
  4.   a := 828;
  5.   b := 653;
  6.   c := 12362752;
  7.   d := 552;        
  8.  
  9.   myResult := ((Int64(a)-b)*c) div d;

Thank you very much, this was the problem... Longint to Int64 and problem is solved.   :D

But I still dont understand: For valid result in Ubuntu is Longint enough, but in Win version of fpc I need Int64?

Apollo286

  • Newbie
  • Posts: 5
Re: Wrong results with Integer numbers math.
« Reply #6 on: January 06, 2021, 12:12:47 am »
...
Because you are operating on a data type that has different sizes on different platforms.
...
Actually, the problem is with the integer multiplication.
...
When Longint is 64bits, there is no overflow.

Thank you for explaining.  :) Your answer is excellent.

wp

  • Hero Member
  • *****
  • Posts: 13397
Re: Wrong results with Integer numbers math.
« Reply #7 on: January 06, 2021, 12:19:28 am »
That is the correct result when Longint is 64bits in size.
This statement confuses me a lot: I always thought that longint is 32 bit: https://www.freepascal.org/docs-html/3.0.2/ref/refsu4.html.

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Wrong results with Integer numbers math.
« Reply #8 on: January 06, 2021, 01:50:12 am »
LongInt is never 64-bit. The reason is how the formula is treated on 64-bt Linux. The result of multiplication is stored to 64-bit register, therefore it gives correct result without overflow even if myResult is 32-bit.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

PascalDragon

  • Hero Member
  • *****
  • Posts: 6349
  • Compiler Developer
Re: Wrong results with Integer numbers math.
« Reply #9 on: January 06, 2021, 11:06:41 am »
Thank you for answer (and sorry for my english).  :)

processor: AMD A10-7800
fpc version:   Ubuntu 20.04 64bit - fpc-laz 3.2.0
                     Windows 10  64bit - fpc 3.2.0
compiler mode: {$mode objfpc}

Are you sure that you're compiling for 64-bit on Windows? Cause I get that result (-3861387) only if I compile for i386.

Also you could enable range and overflow checks (command line options -Cro or directives {$R+}{$Q+}) and you'd see that you got a problem in the case where result is -3861387.

Apollo286

  • Newbie
  • Posts: 5
Re: Wrong results with Integer numbers math.
« Reply #10 on: January 06, 2021, 01:13:13 pm »
Thank you for answer (and sorry for my english).  :)

processor: AMD A10-7800
fpc version:   Ubuntu 20.04 64bit - fpc-laz 3.2.0
                     Windows 10  64bit - fpc 3.2.0
compiler mode: {$mode objfpc}

Are you sure that you're compiling for 64-bit on Windows? Cause I get that result (-3861387) only if I compile for i386.

Also you could enable range and overflow checks (command line options -Cro or directives {$R+}{$Q+}) and you'd see that you got a problem in the case where result is -3861387.

Both systems Ubuntu and Windows are 64bit, but I don't know how the code is compiling on each system (maybe 32-bit on Win and 64-bit on Ubu - I used default installation of Lazarus)...

For me now - after redeclaring variables to Int64, code is working with no integer owerflow.

Bart

  • Hero Member
  • *****
  • Posts: 5702
    • Bart en Mariska's Webstek
Re: Wrong results with Integer numbers math.
« Reply #11 on: January 06, 2021, 01:14:29 pm »
Windows defaults to compiling 32-bit.
On *nix 64-bit you will also have by default a 64-bit compiler.

Bart

lucamar

  • Hero Member
  • *****
  • Posts: 4217
Re: Wrong results with Integer numbers math.
« Reply #12 on: January 06, 2021, 01:50:41 pm »
Windows defaults to compiling 32-bit.

That depends on which installer you did run, doesn't it? If you run the 64 bit one then it'll install the 64bit compiler (and everything else).

Would be nice to see the output of:
Code: [Select]
fpc -i(at least the section "Supported targets") on the OP's Windows install.
« Last Edit: January 06, 2021, 01:57:59 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1575
    • Lebeau Software
Re: Wrong results with Integer numbers math.
« Reply #13 on: January 06, 2021, 07:54:33 pm »
LongInt is never 64-bit.

Good point.  I was thinking of Delphi's LongInt, which does float between 32bit and 64bit sizes depending on platform (whereas Integer and FixedInt are always 32bit).

How does FreePascal handle C-based platform APIs that use 64bit long?

The reason is how the formula is treated on 64-bt Linux. The result of multiplication is stored to 64-bit register, therefore it gives correct result without overflow even if myResult is 32-bit.

Good point.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Wrong results with Integer numbers math.
« Reply #14 on: January 06, 2021, 08:26:53 pm »
You can use the ctypes unit, which includes these:
Code: Pascal  [Select][+][-]
  1. type
  2.   cint8                  = UnixType.cint8;       pcint8                 = UnixType.pcint8;
  3.   cuint8                 = UnixType.cuint8;      pcuint8                = UnixType.pcuint8;
  4.   cchar                  = UnixType.cchar;       pcchar                 = UnixType.pcchar;
  5.   cschar                 = UnixType.cschar;      pcschar                = UnixType.pcschar;
  6.   cuchar                 = UnixType.cuchar;      pcuchar                = UnixType.pcuchar;
  7.  
  8.   cint16                 = UnixType.cint16;      pcint16                = UnixType.pcint16;
  9.   cuint16                = UnixType.cuint16;     pcuint16               = UnixType.pcuint16;
  10.   cshort                 = UnixType.cshort;      pcshort                = UnixType.pcshort;
  11.   csshort                = UnixType.csshort;     pcsshort               = UnixType.pcsshort;
  12.   cushort                = UnixType.cushort;     pcushort               = UnixType.pcushort;
  13.  
  14.   cint32                 = UnixType.cint32;      pcint32                = UnixType.pcint32;
  15.   cuint32                = UnixType.cuint32;     pcuint32               = UnixType.pcuint32;
  16.   cint                   = UnixType.cint;        pcint                  = UnixType.pcint;
  17.   csint                  = UnixType.csint;       pcsint                 = UnixType.pcsint;
  18.   cuint                  = UnixType.cuint;       pcuint                 = UnixType.pcuint;
  19.   csigned                = UnixType.csigned;     pcsigned               = UnixType.pcsigned;
  20.   cunsigned              = UnixType.cunsigned;   pcunsigned             = UnixType.pcunsigned;
  21.  
  22.   cint64                 = UnixType.cint64;      pcint64                = UnixType.pcint64;
  23.   cuint64                = UnixType.cuint64;     pcuint64               = UnixType.pcuint64;
  24.   clonglong              = UnixType.clonglong;   pclonglong             = UnixType.pclonglong;
  25.   cslonglong             = UnixType.cslonglong;  pcslonglong            = UnixType.pcslonglong;
  26.   culonglong             = UnixType.culonglong;  pculonglong            = UnixType.pculonglong;
  27.  
  28.   cbool                  = UnixType.cbool;       pcbool                 = UnixType.pcbool;
  29.  
  30.   clong                  = UnixType.clong;       pclong                 = UnixType.pclong;
  31.   cslong                 = UnixType.cslong;      pcslong                = UnixType.pcslong;
  32.   culong                 = UnixType.culong;      pculong                = UnixType.pculong;
  33.  
  34. {$ifndef FPUNONE}
  35.   cfloat                 = UnixType.cfloat;      pcfloat                = UnixType.pcfloat;
  36.   cdouble                = UnixType.cdouble;     pcdouble               = UnixType.pcdouble;
  37. //  clongdouble            = UnixType.clongdouble; pclongdouble           = UnixType.pclongdouble;
  38. {$endif}
  39.  
  40.   csize_t                = UnixType.size_t;      pcsize_t               = UnixType.psize_t;
  41.  
  42.   coff_t                 = UnixType.TOff;  

 

TinyPortal © 2005-2018