[Lazarus] Cross-compile for Linux strange behaviour with floating point constants

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

[Lazarus] Cross-compile for Linux strange behaviour with floating point constants

Free Pascal - Lazarus mailing list
Hi All,

I'm a long time Lazarus user (since Kylix failed) and a big fan. This is
however my first post on any FPC/Lazarus forum.

The problem I've run into is a simple program (made in Lazarus) where I
use floating point constants. It compiles and runs perfectly on Windows,
but when cross-compiling for Linux, it fails for specific floating point
values.

I realise immediately that, if this is a bug, it's probably an FPC bug
and not Lazarus specific, but the problem is so obviously wrong, I'm
thinking it cannot possibly be a compiler bug, and since I am
cross-compiling from Lazarus, figured I would start asking here and rule
out the obvious things first.

1. My Setup:
Fresh install of Lazarus IDE (SVN Revision 60307 - previous install also
had the problem, so I updated) with FPC 3.04 installed on Windows 10
64bit (x86_64-win64) via fpcupdeluxe with compilers for Windows x86_64
and for Linux x86_64.  I run WSL Ubuntu 19.4 and also 18.4 in a VM and
CentOS7 (because web), and a Linux Mint on my laptop, all of which get
the same error. It compiles and runs perfectly correct in/for Windows.

2. Test case Program:

---------------------------------------------------

program fpbug;

// {$mode objfpc}{$H+}

uses
   Classes, SysUtils, Crt;

// {$R *.res}

var
   x: double;

begin
   // Successful Test:  (Win64 + Linux)
   WriteLn('');
   WriteLn('Setting Variable: x := 0.5; ');
   x := 0.5;
   WriteLn('FloatToStr( x )    --> ',FloatToStr(x));
   WriteLn('FloatToStr( 0.5 )  --> ',FloatToStr(0.5));

   // Failing Test:     (Win64 Pass,  Linux Fail (Ubuntu LTS)
   WriteLn('');
   WriteLn('Setting Variable: x := 0.35; ');
   x := 0.35;
   WriteLn('FloatToStr( x )    --> ',FloatToStr(x));
   WriteLn('FloatToStr( 0.35 ) --> ',FloatToStr(0.35));

end.
----------------------------------------------

I compile with standard debug options first, then production options
(both Windows and Linux with CPU family x86_64 and target Processor
Default)  and had an exhaustive run of enabling/disabling every compiler
switch available in the standard Lazarus "Compilation and Linking"
settings - all to no avail, the problem persists.

3. Windows console Output:

C:\Projects\[LAZARUS]\Temp\ConsoleAppTest>dir /w
  Volume in drive C has no label.
  Volume Serial Number is C234-0116

  Directory of C:\Projects\[LAZARUS]\Temp\ConsoleAppTest

[.]          [..]         [backup]     fpbug        fpbug.dbg
fpbug.exe    fpbug.lpi    fpbug.lpr    fpbug.lps
fpbug.res    fptest       fptest.dbg   fptest.exe   fptest.lpi
fptest.lpr   fptest.lps   fptest.res   [lib]
rc           rc.exe       rc.lpi       rc.lpr       rc.lps
               19 File(s)      2 547 273 bytes
                4 Dir(s)  88 585 740 288 bytes free

C:\Projects\[LAZARUS]\Temp\ConsoleAppTest>fpbug

Setting Variable: x := 0.5;
FloatToStr( x )    --> 0.5
FloatToStr( 0.5 )  --> 0.5

Setting Variable: x := 0.35;
FloatToStr( x )    --> 0.35
FloatToStr( 0.35 ) --> 0.35

C:\Projects\[LAZARUS]\Temp\ConsoleAppTest>


4. Linux console Output:

cuzzy@CUZ-PC64:~/temp/ConsoleAppTest$ ls
backup  fpbug.dbg  fpbug.lpi  fpbug.lps  fptest fptest.exe  fptest.lpr 
fptest.res  rc      rc.lpi  rc.lps
fpbug   fpbug.exe  fpbug.lpr  fpbug.res  fptest.dbg fptest.lpi 
fptest.lps  lib         rc.exe  rc.lpr
cuzzy@CUZ-PC64:~/temp/ConsoleAppTest$ ./fpbug

Setting Variable: x := 0.5;
FloatToStr( x )    --> 0.5
FloatToStr( 0.5 )  --> 0.5

Setting Variable: x := 0.35;
FloatToStr( x )    --> 0.35
FloatToStr( 0.35 ) --> Nan
cuzzy@CUZ-PC64:~/temp/ConsoleAppTest$


As the comments indicate, if I use the constant value 0.5 inside almost
any function that takes a float (Double, Extended, Real, whatever), it
works, both in Windows and Linux.

If I use the value 0.35 (or 0.66667 or 0.333333 - seemingly any number
that has a non-exact round-trip IEEE754 representation, but this is
merely a guess, no exhaustive testing) then in Windows on x86-64 it
still works as expected, but on any Linux version, it returns NaN (as in
my code example) or segfaults or such.

It is perfectly happy for me to assign the value to a variable and then
use the variable (x in the example), but when I use the value directly,
the skullduggery starts.

Tested functions (they all fail for a constant like 0.35): FloatToStr(),
Trunc(), Round(), Ceil(), Floor()


Is there something I can check on my side? Does this work for others? 
Might this be a cross-compile bug of sorts?  Is this some FPC, FPU or
Linux peculiarity I'm not aware of?

Any help or insight would be appreciated - thanks,
Cuz



--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] Cross-compile for Linux strange behaviour with floating point constants

Free Pascal - Lazarus mailing list
Am 20.11.2019 um 19:19 schrieb R Smith via lazarus:
> Is there something I can check on my side? Does this work for others?
> Might this be a cross-compile bug of sorts?  Is this some FPC, FPU or
> Linux peculiarity I'm not aware of?
Win64 is essentially the only x86 platform that does *not* support and
use the Extended type. Thus a cross compiler from x86_64-win64 to any
other i8086, i386 or x86_64 target will result in strange or undefined
behavior due to it not providing the Extended constants correctly. To
solve this you need to compile your code on a Linux system (you can use
WSL without any problems) or make sure that you only use Double (you
also need to cast floating point constants to Double in that case as
otherwise FPC tries to use Extended nevertheless, which is why the
variable in your example works, but the constant does not).

There is the plan to add software floating point support for Extended to
the compiler for platforms like Win64, but it's not a trivial endeavour.
Please note that cross compiling from any other platform that does not
support Extended to x86 will have the same problem (except when cross
compiling to Win64).

Regards,
Sven
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] Cross-compile for Linux strange behaviour with floating point constants

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
Il 20/11/2019 19:19, R Smith via lazarus ha scritto:

> The problem I've run into is a simple program (made in Lazarus) where
> I use floating point constants. It compiles and runs perfectly on
> Windows, but when cross-compiling for Linux, it fails for specific
> floating point values.
>
> I realise immediately that, if this is a bug, it's probably an FPC bug
> and not Lazarus specific, but the problem is so obviously wrong, I'm
> thinking it cannot possibly be a compiler bug, and since I am
> cross-compiling from Lazarus, figured I would start asking here and
> rule out the obvious things first.

I tested your program by compiling natively in Linux, (Lazarus 1.8 and
fpc 3.04) and it works just fine. Output is:
> Setting Variable: x := 0.5;
> FloatToStr( x )    --> 0.5
> FloatToStr( 0.5 )  --> 0.5
>
> Setting Variable: x := 0.35;
> FloatToStr( x )    --> 0.35
> FloatToStr( 0.35 ) --> 0.35
As with the given code Lazarus does pretty much nothing, and all the job
is done by the fpc compiler,
it must be an fpc cross-compiler specific issue.
Target processor "Default" is the right choice? Maybe a more specific
choice will tell the cross-compiler to pick up the right choice for fp
math. Just a guess.

Giuliano

--
Do not do to others as you would have them do to you.They might have different tastes.

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] Cross-compile for Linux strange behaviour with floating point constants

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
Il 24/11/2019 01:17, Sven Barth via lazarus ha scritto:

> There is the plan to add software floating point support for Extended
> to the compiler for platforms like Win64, but it's not a trivial
> endeavour.

Maybe a silly question, but wouldn't it much simpler to have the
compiler not use the Extended type on platforms which do not support it?

Giuliano

--
Do not do to others as you would have them do to you.They might have different tastes.

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] Cross-compile for Linux strange behaviour with floating point constants

Free Pascal - Lazarus mailing list
Am 24.11.19 um 11:45 schrieb Giuliano Colla via lazarus:
> Il 24/11/2019 01:17, Sven Barth via lazarus ha scritto:
>
>> There is the plan to add software floating point support for Extended
>> to the compiler for platforms like Win64, but it's not a trivial
>> endeavour.
>
> Maybe a silly question, but wouldn't it much simpler to have the
> compiler not use the Extended type on platforms which do not support it?

Yes. This is what we do. However, it bites us when cross compiling. What
to do with extended constants and their handling in the compiler if the
target platform has it but the target platform does not support it?

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] Cross-compile for Linux strange behaviour with floating point constants

Free Pascal - Lazarus mailing list
Il 24/11/2019 11:48, Florian Klämpfl via lazarus ha scritto:

> What to do with extended constants and their handling in the compiler
> if the target platform has it but the target platform does not support
> it?

Maybe an AND condition? Use extended type only if both platforms support it?

Giuliano

--
Do not do to others as you would have them do to you.They might have different tastes.

--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] Cross-compile for Linux strange behaviour with floating point constants

Free Pascal - Lazarus mailing list
Am 24.11.19 um 12:04 schrieb Giuliano Colla via lazarus:
> Il 24/11/2019 11:48, Florian Klämpfl via lazarus ha scritto:
>
>> What to do with extended constants and their handling in the compiler
>> if the target platform has it but the target platform does not support
>> it?
>
> Maybe an AND condition? Use extended type only if both platforms support
> it?

This is a no-go. The resulting code/executable must be agnostic
regarding the host where it is generated.
--
_______________________________________________
lazarus mailing list
[hidden email]
https://lists.lazarus-ide.org/listinfo/lazarus