Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2014-05

overloading function

11 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

LacaK

Hi,
I am trying understand how FPC determines which version of overloaded function to call.
Take as example these 2 functions (from SysUtils):
1. function StrPLCopy(Dest: PChar; Source: string; MaxLen: SizeUInt): PChar; overload;
2. function StrPLCopy(Dest: PWideChar; const Source: UnicodeString; MaxLen: SizeInt): PWideChar; overload;

And in program I use:
var p: pointer;
      s: string;
begin
   StrPLCopy(p, s, 10);
end;

It seems, that 2nd "unicode" version of StrPLCopy is called. But why? I am thinking as:
1st parameter is untyped pointer, so no one of function can be prefered 2nd parameter is "string" which exactly match 1st function signature 3rd parameter is "integer constant" which mach both signatures

So it seems to me, that 1st version of function signature matches better, because of exact match of 2nd parameter ... why is then called 2nd version?
-Laco.

Reply by email

Sven Barth
to LacaK
LacaK wrote 25 lines
Hi, I am trying understand how FPC determines which version of overloaded function to call. Take as example these 2 functions (from SysUtils): 1. function StrPLCopy(Dest: PChar; Source: string; MaxLen: SizeUInt): PChar; overload; 2. function StrPLCopy(Dest: PWideChar; const Source: UnicodeString; MaxLen: SizeInt): PWideChar; overload; And in program I use: var p: pointer; s: string; begin StrPLCopy(p, s, 10); end; It seems, that 2nd "unicode" version of StrPLCopy is called. But why? I am thinking as: 1st parameter is untyped pointer, so no one of function can be prefered 2nd parameter is "string" which exactly match 1st function signature 3rd parameter is "integer constant" which mach both signatures So it seems to me, that 1st version of function signature matches better, because of exact match of 2nd parameter ... why is then called 2nd version?

I don't have a explanation for now, but it *might* be important to note whether you are using 2.6.x or 2.7.1.

Regards,
Sven

Reply by email

LacaK
to Sven Barth: I don't have a explanation for now, but it *might* be important to note whether you are…

Hi again,
I reply also to fpc-devel list (excuse me, if it is off-topic), because I would like understand wat is going on.
I attach also simple test program.
I use FPC 2.6.4 but I think, that same happens also with fresh 2.7.1 Thanks
-Laco.

Show quoted text 37 lines
On 02.05.2014 07:45, LacaK wrote: > Hi, > I am trying understand how FPC determines which version of overloaded > function to call. > Take as example these 2 functions (from SysUtils): > 1. function StrPLCopy(Dest: PChar; Source: string; MaxLen: SizeUInt): > PChar; overload; > 2. function StrPLCopy(Dest: PWideChar; const Source: UnicodeString; > MaxLen: SizeInt): PWideChar; overload; > > And in program I use: > var p: pointer; > s: string; > begin > StrPLCopy(p, s, 10); > end; > > It seems, that 2nd "unicode" version of StrPLCopy is called. But why? > I am thinking as: > 1st parameter is untyped pointer, so no one of function can be prefered > 2nd parameter is "string" which exactly match 1st function signature > 3rd parameter is "integer constant" which mach both signatures > > So it seems to me, that 1st version of function signature matches > better, because of exact match of 2nd parameter ... why is then called > 2nd version? I don't have a explanation for now, but it *might* be important to note whether you are using 2.6.x or 2.7.1. Regards, Sven _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply by email

LacaK
to LacaK

When I change definition of 3rd parameter in unicode version of StrPLCopy from SizeInt to SizeUInt, then in my example program is correctly called "ansi version"
So it seems, that this 3rd parameter confused compiler and somehow forced him to prefer wrong version...?
-Laco.

Show quoted text 46 lines
Hi again, I reply also to fpc-devel list (excuse me, if it is off-topic), because I would like understand wat is going on. I attach also simple test program. I use FPC 2.6.4 but I think, that same happens also with fresh 2.7.1 Thanks -Laco. > On 02.05.2014 07:45, LacaK wrote: >> Hi, >> I am trying understand how FPC determines which version of overloaded >> function to call. >> Take as example these 2 functions (from SysUtils): >> 1. function StrPLCopy(Dest: PChar; Source: string; MaxLen: SizeUInt): >> PChar; overload; >> 2. function StrPLCopy(Dest: PWideChar; const Source: UnicodeString; >> MaxLen: SizeInt): PWideChar; overload; >> >> And in program I use: >> var p: pointer; >> s: string; >> begin >> StrPLCopy(p, s, 10); >> end; >> >> It seems, that 2nd "unicode" version of StrPLCopy is called. But why? >> I am thinking as: >> 1st parameter is untyped pointer, so no one of function can be prefered >> 2nd parameter is "string" which exactly match 1st function signature >> 3rd parameter is "integer constant" which mach both signatures >> >> So it seems to me, that 1st version of function signature matches >> better, because of exact match of 2nd parameter ... why is then called >> 2nd version? > > I don't have a explanation for now, but it *might* be important to > note whether you are using 2.6.x or 2.7.1. > > Regards, > Sven > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal >

Reply by email

Bruno Krayenbuhl
to LacaK

You have troubled me seriously, so I have dug in the compiler source.

It appears that when parsing the source, Currency constants are cast to type BestReal (EXTENDED on I386) before being converted to the 8 byte currency written to the PPU or EXE or whatever is done. The combination of these steps DO USE FPU instructions on the I386, the compiler does not use SysUtils.StrToCurr to create the 8 bytes currency.

As a bean counter, the point that was really scaring me was whether additions and subtractions of Currency's with Currency's would use the FPU. It appears that the generated (ASM) code actually uses Int64 arithmetic's for these 2 operations. Ouf...

I run FPC 2.6.4 on WinXP machine with an Intel Core 2 CPU 6400 @2.13 GHz s

Here after a program that should test if the compiler is run on a problematic CPU

==============================================

program test_Currency_loop;
var
  c:currency;
  cAsInt:Int64;
  // cAsInt64:Int64 absolute c;
  ix:integer;
begin
  c:=92233720368547;
  cAsInt:=922337203685470000;
  if Pint64(@c)^cAsInt then
    WriteLn('Problematic CPU for Compiler'); // FPU error on machine running
the compiler Dbg stop point
  writeln(c);
  for ix:=1 to 9 do begin
    c:=c+0.0001;
    writeln(c);
 end;
  readln;
end.
==============================================

To test :

1-Compile and run on your XP machine. Copy the .EXE to your W98 machine and run it. See the results.

2-Compile and run on your Win98 machine. Copy the W98 .EXE to your XP machine and run it. See the results.

I pop my stack and go back to what I was working on.

Regards, Bruno

Reply by email

LacaK
to Bruno Krayenbuhl
You have troubled me seriously, so I have dug in the compiler source.

:-)

Show quoted text 5 lines
It appears that when parsing the source, Currency constants are cast to type BestReal (EXTENDED on I386) before being converted to the 8 byte currency written to the PPU or EXE or whatever is done.

it was my expectation also

Show quoted text 51 lines
The combination of these steps DO USE FPU instructions on the I386, the compiler does not use SysUtils.StrToCurr to create the 8 bytes currency. As a bean counter, the point that was really scaring me was whether additions and subtractions of Currency's with Currency's would use the FPU. It appears that the generated (ASM) code actually uses Int64 arithmetic's for these 2 operations. Ouf... I run FPC 2.6.4 on WinXP machine with an Intel Core 2 CPU 6400 @2.13 GHz s Here after a program that should test if the compiler is run on a problematic CPU ============================================== program test_Currency_loop; var c:currency; cAsInt:Int64; // cAsInt64:Int64 absolute c; ix:integer; begin c:=92233720368547; cAsInt:=922337203685470000; if Pint64(@c)^cAsInt then WriteLn('Problematic CPU for Compiler'); // FPU error on machine running the compiler Dbg stop point writeln(c); for ix:=1 to 9 do begin c=c+0.0001 writeln(c); end; readln; end. ============================================== To test : 1-Compile and run on your XP machine. Copy the .EXE to your W98 machine and run it. See the results.

Compiled on WinXP with FPC 2.6.4 (CPU Intel Core 2 Duo). Results: 9.223372036854700000E+13
9.223372036854700010E+13
9.223372036854700020E+13
9.223372036854700030E+13
9.223372036854700040E+13
9.223372036854700050E+13
9.223372036854700060E+13
9.223372036854700070E+13
9.223372036854700080E+13
9.223372036854700090E+13

When I run it on Win98 I get same result as for WinXP (correct).

2-Compile and run on your Win98 machine. Copy the W98 .EXE to your XP machine and run it. See the results.

Compiled on Win98 with FPC 2.6.4 (CPU Intel Pentium 4). Results: Problematic CPU for Compiler
9.223372036854699520E+13
9.223372036854699530E+13
9.223372036854699540E+13
9.223372036854699550E+13
9.223372036854699560E+13
9.223372036854699570E+13
9.223372036854699580E+13
9.223372036854699590E+13
9.223372036854699600E+13
9.223372036854699610E+13

When I run it on WinXP I get same result as for Win98 (incorrect).

BUT! When I try it (compile and run) on other computer with Win98 (old CPU Celeron) then results are correct as in step 1!!!

So what is your conclusion ?
I do not think, that culprit is CPU or Win98, but compiler on my PC with Win98 must be somehow confused by something else in my PC ... may be any DLL hell (does compiler links some external DLL (from system folder?) during compilation) ?

I pop my stack and go back to what I was working on.

Thanks for your time.

-Laco.

Reply by email

LacaK
to Pierre Free Pascal
Show quoted text 18 lines
Did you check that infamous coprocessor Pentium FDIV bug? http://en.wikipedia.org/wiki/Pentium_FDIV_bug#Affected_models The even give values to test: The correct value is 4195835/3145727 = 1.333820449136241002 However, the value returned by the flawed Pentium is incorrect at or beyond four digits:[9] 4195835/3145727 = 1.333739068902037589 Maybe that is your problem?

Thank you Pierre for idea!
But it is not my problem. I get correct results:
for extended: 1.3338204491362411E+0000
for fouble: 1.33382044913624E+000

Because I do not have "old" Pentium CPU, but newer GenuineIntel Intel(R) Celeron(R) CPU 1.70GHz [x86 Family 15 Model 1 Stepping 3] Thanks
-Laco.

Reply by email

Bruno Krayenbuhl
to Pierre Free Pascal: Did you check that infamous coprocessor Pentium FDIV bug?…

Lets restate the hole thing, considering unit ncon.pas and pexpr.pas units in FPC 2.6.4
compiler.

1° It is not possible, without using some ad hoc adjustements, to have always an EXACT CURRENCY stored in a DOUBLE or EXTENDED because Double or Extended being expressed as Sign*2^exp*Base2(n). Just start with 0.1 to see what I mean.

2° trealconstnode class stores the currency_literal value to value_real (type bestreal) then converts it to value_currency either in the trealconstnode.create or sets it in pexpr.pas function factor(getaddr,typeonly:boolean) : tnode; just after {$ifdef FPC_HAS_STR_CURRENCY}

3° c:=92233720368547; // The original problem
multiple operations involve *10000 (OK per see) and /10000 (not so good) while parsing the constant to bestreal type before generating .EXE code. (bestreal is Extended on Intel I386 and Up and Double on ARM).

4° The compiler will not compain about Currency_Value:=0.99999 whereas the
max decimal precision is 0.9999 for decimal part.

5° What I found is that only + or - operations on Currency's giving a Currency will be generated with plain Int64 addition and subtractions.

Now what ?

It would be interesting that someone who has an ARM based machine/compiler do
some testing.

Since currency is a very good type for accounting, you know Sum(Assets)-Sum(Liabilities)=Sum(Incomes)-Sum(Costs) -> hopefully benefit and exact,
some workarounds must be found.
A basic way to circumvent the risks when absolutly necessary would be something like what is decribed next, not very Pascal clean I must admit :

- Insure that the compiler will not see a literal currency when assigning or calculating a precise value containing a literal currency value.

so short example, look at the ASM code generated.

var
 c: currency;
 lInt64:Int64 absolute c; // Avoid use of Currency
begin
  c:=0.99999; // Accepted by the compiler ... and rounded to 1
  c:=0.99986; // Accepted by the compiler ... and rounded to 0.9999
  c:=0.99984; // Accepted by the compiler ... and rounded to 0.9998
  { The easy way but uses the FPU }
  c:=92233720368547; // <- that might be wrongly evaluated by the Compiler
(FPU usage) but nothing will be visible in the generated ASM regarding FPU
evaluation, except in your case, an invalid HEX value
  c:=c+0.01; // <- uses FPU
  writeln('c+0.01 with FPU=', c);
  { Clumsy but no FPU usage while compiling and executing }
  lInt64:=922337203685470000; // <- You can test but my bet is that it
probably always correctly evaluated by the compiler
  lInt64:=lInt64+100; // Equivalent to c:=c+0.01
  writeln('c+0.01 indirect no FPU=', c);
  readln;
end;

Your subject has been interesting and I'll be careful now with rounding and Currency.

Regard Bruno.

Reply by email

LacaK
to Bruno Krayenbuhl
Show quoted text 9 lines
Lets restate the hole thing, considering unit ncon.pas and pexpr.pas units in FPC 2.6.4 compiler. 1° It is not possible, without using some ad hoc adjustements, to have always an EXACT CURRENCY stored in a DOUBLE or EXTENDED because Double or Extended being expressed as Sign*2^exp*Base2(n). Just start with 0.1 to see what I mean.

Yes I understand it

Show quoted text 63 lines
2° trealconstnode class stores the currency_literal value to value_real (type bestreal) then converts it to value_currency either in the trealconstnode.create or sets it in pexpr.pas function factor(getaddr,typeonly:boolean) : tnode; just after {$ifdef FPC_HAS_STR_CURRENCY} 3° c:=92233720368547; // The original problem multiple operations involve *10000 (OK per see) and /10000 (not so good) while parsing the constant to bestreal type before generating .EXE code. (bestreal is Extended on Intel I386 and Up and Double on ARM). 4° The compiler will not compain about Currency_Value:=0.99999 whereas the max decimal precision is 0.9999 for decimal part. 5° What I found is that only + or - operations on Currency's giving a Currency will be generated with plain Int64 addition and subtractions. Now what ? It would be interesting that someone who has an ARM based machine/compiler do some testing. Since currency is a very good type for accounting, you know Sum(Assets)-Sum(Liabilities)=Sum(Incomes)-Sum(Costs) -> hopefully benefit and exact, some workarounds must be found. A basic way to circumvent the risks when absolutly necessary would be something like what is decribed next, not very Pascal clean I must admit : - Insure that the compiler will not see a literal currency when assigning or calculating a precise value containing a literal currency value. so short example, look at the ASM code generated. var c: currency; lInt64:Int64 absolute c; // Avoid use of Currency begin c:=0.99999; // Accepted by the compiler ... and rounded to 1 c:=0.99986; // Accepted by the compiler ... and rounded to 0.9999 c:=0.99984; // Accepted by the compiler ... and rounded to 0.9998 { The easy way but uses the FPU } c:=92233720368547; // <- that might be wrongly evaluated by the Compiler (FPU usage) but nothing will be visible in the generated ASM regarding FPU evaluation, except in your case, an invalid HEX value c:=c+0.01; // <- uses FPU writeln('c+0.01 with FPU=', c); { Clumsy but no FPU usage while compiling and executing } lInt64:=922337203685470000; // <- You can test but my bet is that it probably always correctly evaluated by the compiler lInt64:=lInt64+100; // Equivalent to c:=c+0.01 writeln('c+0.01 indirect no FPU=', c); readln; end; Your subject has been interesting and I'll be careful now with rounding and Currency.

:-) Thanks Bruno for your detailed insight

For now I lost patience and have reinstalled Win98 on same computer (same CPU)
I have again reinstalled Lazarus 1.2.2 + FPC 2.6.4 And recompile test application again.
Now are results correct !!!

So culprit was not OS nor CPU but something else has to be wrong. I will carefully install other applications and check if problem will again appears.
For now I have no idea what has confused FPC to generate wrong binary representation of mentioned currency value.

-Laco.

Reply by email