Recent

Author Topic: Log10 in FPC versus Log10 in Delphi question. Also need FPC/DCC Guidelines  (Read 7765 times)

gues1

  • Guest
@Thaddy: from the thread, was not clear if Delphi versions before 12 can be forced to return +/-Inf instead of generating exception.
This has been around for many, many years.
The problem is that some "operations" were poorly defined by IEEE 754, leaving room for bugs.
Furthermore, RTLs were not fully optimized, so operating only with masked exceptions  was virtually impossible.

Paolo

  • Hero Member
  • *****
  • Posts: 693
But try except is not tought to check single operation, it sorrounds a lot of code, and thus is less expensive than check everything. It catches invalid computation unexpected let me say. Do you think that in code runnig for hours you check if any computations the result can be valid ?
« Last Edit: July 24, 2025, 08:12:11 pm by Paolo »

Thaddy

  • Hero Member
  • *****
  • Posts: 18930
  • Glad to be alive.
That is a complete misunderstanding of try/except.
The code inside the try should be as minimal as possible and the code in the except should be as precise as possible.
What you write is really, really bad programming.

And don't start an argument, I am right.
« Last Edit: July 24, 2025, 08:41:33 pm by Thaddy »
Recovered from removal of tumor in tongue following tongue reconstruction with a part from my leg.

Paolo

  • Hero Member
  • *****
  • Posts: 693
if you are doing few computation is better to go as Khrys suggested, so check the precondition before doing the computation

I added a modification (am I right ?)
Code: Pascal  [Select][+][-]
  1. implementation
  2.  
  3. uses
  4.   Math;
  5.  
  6. function Log10(X: Double): Double;
  7. begin
  8.   if X > 0 then
  9.     Result := Math.Log10(X)
  10.   else
  11.      if X = 0 then
  12.         Result := -Infinity
  13.      else
  14.         Result:=NAN
  15. end;
  16.  

but if you go for heavy computatiomn with several tons of input data and porcessing stages it is not efficient to test everything, better to chatch the exception to abort the whole sequence.

Paolo

  • Hero Member
  • *****
  • Posts: 693
but if you set the excpetionmask as Thaddy said the reult is already there without custom log10 function

here the two versions

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.  x, y :  Double;
  4.  Str1 : string;
  5. begin
  6.   x:=-1;
  7.   y:=1;
  8.   SetExceptionMask(GetExceptionMask + [exInvalidOp, exZeroDivide]);
  9.   y:=log10(x);
  10.   str1:=y.tostring;
  11.   button1.caption:=Str1;  //<-- here number, -inf or NAN
  12.  
  13.   x:=-1;
  14.   y:=1;
  15.   SetExceptionMask(GetExceptionMask - [exInvalidOp, exZeroDivide]);
  16.   y:=log10(x);                 //<--- here the exception is raised
  17.   str1:=y.tostring;
  18.   button1.caption:=Str1;
  19. end;
  20.  

Thaddy

  • Hero Member
  • *****
  • Posts: 18930
  • Glad to be alive.
And that is the proper solution. The problem is wider than just log10:
Modern Delphi masks all floating point exceptions and that is as per IEEE754-2019. Most other compilers do.
Delphi has provided a Legacy mask to avoid breaking older code. (Well, that is the least they could do because it is, as I explained, a breaking change.)
So the fix should never be for just log10. Further more, fixing it at fpu level is much faster than above code: flags as opposed to a relatively expensive comparison.
I decided to write a bug report after all, since the issue is more like hindsight from the standards commission than it is a Freepascal issue perse.
Applying the mask is valid for all cases where a division by zero/  and/or +/-inf/NaN can occur.

I reported it as :
#41341

Note, as I explained in the bug report, it is not a bug perse' but an implementation consideration.
« Last Edit: July 26, 2025, 11:50:24 am by Thaddy »
Recovered from removal of tumor in tongue following tongue reconstruction with a part from my leg.

d2010

  • Sr. Member
  • ****
  • Posts: 264
if you are doing few computation is better to go as Khrys suggested, so check the precondition before doing the computation

C:q1=I added a modification (am I right ?)
Code: Pascal  [Select][+][-]
  1. Function spin_log10s(x:double;out errcode:char):double;
  2. begin
  3.   errcode:='e';
  4.   if X > 0 then  
  5.    Begin Result:=Math.Log10(X); errcode:='a';End
  6.   else Begin result:=0.0;
  7.         if X = 0 then errcode:='E';
  8.        End;
  9. end;
  10.  
  11. Var asf_log10s:char='a';
  12. Function acgs_log10s(x:double):double;
  13. begin
  14.   errcode:=#13;
  15.   if X > 0 then begin Result := Math.Log10(X);asf_log10s:='A';End
  16.   else Begin result:=0.0;
  17.         if X = 0 then asf_log10s:=#10
  18.        End;
  19. end;
  20.  
For speed, You must use acgs_log10s, for a few less, speed then You can spin_log10s
I hope , you have right ,compare the 10000X*double as NAN(s) or -Infinite(s) is more
slow-down your lpr, Even the compare 10000X*char+after+10000X*double as NAN, I hope is more better. :-\
E.g.You can only last 255 "store all asf_log10s" inside one big-string
Doamne ajuta.
Code: [Select]
Var asferror:array[0..255] of char;
     index:integer=000;
*cHb_Canal, Taluz Canal --------Taluz Canal --------Taluz Canal --------Taluz Canal --------
 begin
   asf_log10s:='b';
    Chars := PChar(
      Format(
        Format('%%.%du', [Max(8, Trunc(acgs_Log10s(AState.Score)))]),
        [AState.Score]));
   asferror[index and 255] :=asf_log10s;
   inc(index);
    TextDimensions := MeasureTextEx(FontInterlaced, Chars, FontSize, 1);
    Rectangle.width := TextDimensions.x * 1.05;
    Rectangle.height := TextDimensions.y * 1.1 - 2;
    Rectangle.x := 2;
    Rectangle.y := 2;
[/b]

« Last Edit: July 26, 2025, 12:22:32 pm by d2010 »

Thaddy

  • Hero Member
  • *****
  • Posts: 18930
  • Glad to be alive.
Excuse me for shouting but THAT IS HORRIBLE. Read my bug report. That explains what needs to be done and why.
It is highly technical and you need to understand IEEE754-2008 and IEEE754-2019 to interpret the issue at hand.
Recovered from removal of tumor in tongue following tongue reconstruction with a part from my leg.

Paolo

  • Hero Member
  • *****
  • Posts: 693
@d2010, not sure to have correctly understood what you mean.

I am in favor of exception usage, and not wasting time into check "by hand" if something went wrong.

in particular if you have enabled "NAN" and friends, and do not check maniacally every single computation step, you can discover too late, that all went wrong may time ago (eg at initial computation time)

I stressed that I am interested on very huge computation.

Obviously, I can image that the usage of "NAN" and friends can be useful (when ?) in some specific computation areas, whereas in my case they are clear symptom of "something wrong" that can be easily captured by exceptions

that's all.


Paolo

  • Hero Member
  • *****
  • Posts: 693
@Thaddy,
I remeber in the bug tracker that the dev are aware of this, and decided to wait to see how the things evolved (as you pointed out at the moment the major point of concern is the compatibility with existent code)

Paolo

  • Hero Member
  • *****
  • Posts: 693
see #40527 "Delphi 12 changes in default floating point behaviour."

Thaddy

  • Hero Member
  • *****
  • Posts: 18930
  • Glad to be alive.
Could not find that, tnx! but my report adds something to it, namely that the industry accepted it as standard.
As such it is not Delphi, but the IEEE754-2019 that is the culprit.
The developers are usually more receptive to proper documentation that lead to the change that Delphi has made.
Probably also influenced by 1. their C++ compiler 2. their LLVM back-end which are both more likely to follow standards.
I tried to explain that in a lot more detail, not confined to Delphi compatibility.
I made the reports related.
« Last Edit: July 26, 2025, 01:14:07 pm by Thaddy »
Recovered from removal of tumor in tongue following tongue reconstruction with a part from my leg.

gues1

  • Guest
I am in favor of exception usage, and not wasting time into check "by hand" if something went wrong.
in particular if you have enabled "NAN" and friends, and do not check maniacally every single computation step, you can discover too late, that all went wrong may time ago (eg at initial computation time)
I stressed that I am interested on very huge computation.
Obviously, I can image that the usage of "NAN" and friends can be useful (when ?) in some specific computation areas, whereas in my case they are clear symptom of "something wrong" that can be easily captured by exceptions
that's all.
You 'll behave in that way whenever you want also if the default way of Lazarus / FPC change: the standard changed, don't forget this, not Delphi or others (I mean that Delphi followed the standard).

But if Lazarus / FPC don't work to adapt all the things you were not able to fully works in the new way.

Until Delphi 12, I used all the external math libraries in threads to work ('cause mask exceptions). Now I work with less threads too.

This is not a problem if you make your own code ... you make a code, so you can do what you want.
It's an issues if you work with external libs.

Paolo

  • Hero Member
  • *****
  • Posts: 693
That is clear, and I am aware of it.

In any case, out of curiosità, can you provide an example where using inf, nan, etc.. is useful ? I am pretty sure that should be...

Thaddy

  • Hero Member
  • *****
  • Posts: 18930
  • Glad to be alive.
It is useful anywhere, because exceptions are way more expensive than comparisons, so a comparison against -inf - if needed at all! - in the case of div by zero is much much faster. That is also the reason why the IEEE754 has changed.
It is a bit like {$I-} vs {$I+} where reading IOResult is much, much faster than structured exceptions.(which are misused all over the place anyway).
Calculations with -inf will by definition end up having -/+ inf or NaN. And so can be discarded as not valid.
(A multiplication by zero is always -inf, any operation with Infinity or NaN is infinity + or - or NaN, if NaN is involved, answer is always NaN.)

The above is simply general information that is available on any math website and even wikipedia does a good job.
« Last Edit: July 26, 2025, 03:43:17 pm by Thaddy »
Recovered from removal of tumor in tongue following tongue reconstruction with a part from my leg.

 

TinyPortal © 2005-2018