Recent

Author Topic: Trivial 64 bits maths  (Read 608 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 8504
Trivial 64 bits maths
« on: October 09, 2024, 06:08:39 pm »
Using FPC 3.2.2 on x86_64 Linux, I have this:

Code: Text  [Select][+][-]
  1.  in acceptable) do begin
  2.     scratch *= radix;
  3.     if s[1] <= '9' then
  4.       scratch := scratch + (Ord(s[1]) - Ord('0')) // <------------------
  5.     else
  6.       scratch := scratch + (Ord(LowerCase(s[1])) - Ord('a') + 10);
  7.     Delete(s, 1, 1);
  8.     q += 1                              (* Count of digits parsed            *)
  9.   end;
  10.  

That is, obviously, from a number parser which I'm extending from 32-bits to 64 (and hopefully later more).

At the indicated line the string variable s contains the single character '5', and scratch contains $9E3779B97F4A7C10.

That's16 hex digits, and the final one is zero.

Even with all runtime checks disabled, it results in "Range check error".

Why?

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

MarkMLl

  • Hero Member
  • *****
  • Posts: 8504
Re: Trivial 64 bits maths
« Reply #1 on: October 09, 2024, 07:21:09 pm »
Found it I think. It was one of those elusive red herrings that's caused multiple people problems: the location of the unit containing the failing code was defined like

Code: Pascal  [Select][+][-]
  1. uses
  2.   ParseNumbers in '../parsenumbers.pas';
  3.  

and /something/ wasn't being rebuilt... apparently even after manually removing all .o and .ppu files.

The code still generates an exception if either "Verify Method Calls" or "Range" checks are enabled, but at least now I have a reproducible situation which I think can be worked around.

Updated: Ummm... Can anybody confirm that {$r- } does both of these together?

MarkMLl
« Last Edit: October 09, 2024, 07:32:08 pm by 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

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11793
  • Debugger - SynEdit - and more
    • wiki
Re: Trivial 64 bits maths
« Reply #2 on: October 09, 2024, 07:27:51 pm »
Even with all runtime checks disabled, it results in "Range check error".

That doesn't sound right. Sure you don't have them somewhere? in some other config that gets somehow used?

Because I have plenty of code where I know that range checks and overflows happen (and where I want the 64 bit result of that). And there are no errors like that. I surround such code with
Code: Pascal  [Select][+][-]
  1. {$push}{$Q-}{$R-}
  2. ...
  3. {$pop}

That said, you hex number is a negative 64bit num, if I am not mistaken? Is it stored in an int64 or qword?

I haven't tested but if the ord() is treated as signed and gets handled as int64 then you maybe have "qword - int64" with a qword value that can not be converted to int64. Or something similar.

Maybe add typecasts to the result of the "qword(ord(...) - ord('0'))". Or Int64 if your big number is int64.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8504
Re: Trivial 64 bits maths
« Reply #3 on: October 09, 2024, 07:40:21 pm »
Even with all runtime checks disabled, it results in "Range check error".

That doesn't sound right. Sure you don't have them somewhere? in some other config that gets somehow used?

Because I have plenty of code where I know that range checks and overflows happen (and where I want the 64 bit result of that). And there are no errors like that. I surround such code with
Code: Pascal  [Select][+][-]
  1. {$push}{$Q-}{$R-}
  2. ...
  3. {$pop}

That said, you hex number is a negative 64bit num, if I am not mistaken? Is it stored in an int64 or qword?

I haven't tested but if the ord() is treated as signed and gets handled as int64 then you maybe have "qword - int64" with a qword value that can not be converted to int64. Or something similar.

Maybe add typecasts to the result of the "qword(ord(...) - ord('0'))". Or Int64 if your big number is int64.

Pretty sure, in the end I used  find  to expunge all .o and .ppu files but only managed to get rid of it when I focused in  uses...in. And everything is already carefully being done as qwords.

I can now reproducibly enable and disable the problem using {$r- }... or by changing the setting of the two debugging flags from the IDE. But I'm not finding it easy to get it in a standalone demo program.

Updated: Just in case it ever turns out useful, the uses...in clause was in an include file which was pulled into a program unit that basically did nothing except set up a dozen or so macros. Xref to https://forum.lazarus.freepascal.org/index.php/topic,56582.msg420488.html#msg420488 which itself points to other threads, the most significant things being that a lot of confusion is apparently being caused by uses...in and unitpath etc. Under the circumstances, I for one would prefer not to speculate on whether it's FPC, the Lazarus IDE or users being confused :-)

MarkMLl
« Last Edit: October 09, 2024, 10:12:26 pm by 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

 

TinyPortal © 2005-2018