Jump to content

pmcgee

Members
  • Content Count

    70
  • Joined

  • Last visited

  • Days Won

    2

Posts posted by pmcgee


  1. const and const[ref] work differently in this case  (for example) :   

    procedure Proc(const nValue: Integer);
    var
      pValue: ^Integer;
    begin
      writeln(integer(@nvalue));
      pValue := @nValue;
      pValue^:= nValue*2;
    end;
    
    begin
       var x:=1;
       writeln(x, '  ', integer(@x));
       proc(x);
       writeln(x);
       readln;
    end.

    'Const' case prints '1 1', and const[ref] prints '1 2'


  2. On 5/12/2025 at 8:38 AM, Stefan Glienke said:

    build version three of your routines that have their parameter as var

    Good point. I had overlooked that case. 

     

    On 5/12/2025 at 8:38 AM, Stefan Glienke said:

    if you retrieve the address of a parameter or variable that resides in a register, the compiler will reserve stack space for it to retrieve the address of it.

    I see what you are saying ... but I haven't worked out what I think as a result.
    I was looking at the disassembly side by side for four cases ... until a Windows forced a restart on me.
    Ah ... actually I was using Google Sheets instead of Excel : https://docs.google.com/spreadsheets/d/1ZGJ6seGZR_zNO_mpke6733fHGgOVhoM6PH_q1x7tJB8/edit?usp=sharing    (I hadn't finished tracing through all the steps.)


  3. One thing I noticed about Const[ref] relates to 'reference shadowing' (maybe there's a better term).

     

    If you call a function/procedure that takes a const string, the function uses a new reference to the string.

    With const[ref] it uses the exact existing reference.

     

     

     

    {$APPTYPE CONSOLE}
    program Project1;
    uses
      system.SysUtils,
      System.Generics.Collections;
    
    type
      pr = TPair<integer,integer>;
    
    procedure call_i1 (     const x:integer);  begin  writeln( integer(@x) );  end;
    procedure call_i2 (const[ref] x:integer);  begin  writeln( integer(@x) );  end;
    procedure call_c1 (     const x:TObject);  begin  writeln( integer(@x) );  end;
    procedure call_c2 (const[ref] x:TObject);  begin  writeln( integer(@x) );  end;
    procedure call_s1 (     const x:string);   begin  writeln( integer(@x) );  end;
    procedure call_s2 (const[ref] x:string);   begin  writeln( integer(@x) );  end;
    procedure call_p1 (     const x:pr);       begin  writeln( integer(@x) );  end;
    procedure call_p2 (const[ref] x:pr);       begin  writeln( integer(@x) );  end;
    
    begin
      var i : integer;
      var o : TObject;
      var p : pr;
      var s : string;
    
      writeln( integer(@i) ); call_i2(i); call_i1(i); writeln;
      writeln( integer(@o) ); call_c2(o); call_c1(o); writeln;
      writeln( integer(@s) ); call_s2(s); call_s1(s); writeln;
      writeln( integer(@p) ); call_p2(p); call_p1(p);
    
      readln;
    end.

    For TPair, the const[ref] makes no difference ... but for string, integer, and Class, it uses the address of the original value or reference.

     

    Quote

    int   11533168
    int   11533168
    int   11533128

     

    class 11533164
    class 11533164
    class 11533128

     

    str   11533152
    str   11533152
    str   11533128

     

    tpair 11533156
    tpair 11533156
    tpair 11533156

     


  4. There is a section of the programming community, from eg Alexander Stepanov, to eg Jason Turner (of C++Weekly)
     

    That consider implicit conversion to be evil, or a safety issue. (https://news.ycombinator.com/item?id=24806884)

    (Google shows me links about it from 2005, 2010, 2015, and 2020 🙂 )

    I guess their argument is for explicit casts (if absolutely necessary), over what might be termed 'a wing and a prayer'. 

     

    Certainly this works :  

    S := 'Testing: ' + string(V);

     


  5. On 4/13/2025 at 3:37 PM, Kas Ob. said:

     

    4) I don't understand from where the assumption of only 48 bits are only used, this is strange and out of the context or this family of PRNG, may be i missed something with Bits, but will not dig deeper in it.

     

    The original Github repo (https://github.com/rvelthuis/DelphiBigNumbers) has a pdf by Rudy explaining the library. And it says this :

    Quote

    IRandom
    I was not sure how to generate a random BigInteger. Other languages seem to use separate Random classes for this. I wanted to avoid any
    manual memory management for random numbers, so I declared an interface (called, you guessed it, IRandom) with a few suitable methods
    and two implementations, the first being TRandom, using the simple algorithm Knuth proposes and which Java seems to use (using an 48 bit
    seed
    ) and the second, TDelphiRandom, which uses the built-in System.Random functions to generate random values. Both classes can be found
    in unit RandomNumbers.pas, included in the download. If you want to create your own, inherit from TRandom and override the virtual
    parameterless function Next().

     

    • Like 1

  6. Quote

    Literally the definition of Karatsuba, to split in half and perform on half length 

    Yes. Right. Got it.

    I did go to the link, but my brain saw the (az+b)(cz+d) and totally failed to see that this was exactly the z = 1.e32 (in binary) that I was using. 

     

    And thank you for the information about the Elliptic Curve stuff (El-Gamal) to read up on.  I'll be very interested to read it.

    • Like 1

  7. Quote

    6) tried to figure out this code ... You are going with Karatsuba 

    No, I don't think so. I was just doing the multiplication in pieces that didn't overflow 64 bits.
    I was just taking a multiplication of two 64-bit numbers, and thinking of it kinda like a long multiplication from school.

     

    If we consider each number in their two halves (upper and lower 32 bits), then when we only want to keep the bottom 64-bits, we can throw away part of the multiplications ...

    and do some of the multiplication in the lower part of the range before shifting it back up again.

     

    Quote

    yet the last masking is again wrong assuming

    Yes. I was going to be potentially incorrect in the 64th bit, but it was easy to do, and wasn't affecting the testing I had done to that stage.

     

     

     

    Quote

    About learning and implementing RSA, yes do it and you will learn much, and i wish you good luck.
    ... if you are going to use you own implementation of RSA in production for clients ...

    No, not at all.  I have been, with friends, going through Alexander Stepanov's book (and related videos) "From Mathematics to Generic Programming", and he describes RSA in there.

    We set ourselves the task to implement it in different languages.

    Its pretty remarkable how simple the mechanical parts are (in concept).

     

    image.thumb.png.3cf6822042d5a5f411dd480d50005794.png


  8. 17 hours ago, pmcgee said:

     

    
    {$IFOPT Q+}                                                          
    {$DEFINE HasRangeChecks}                                           
    {$ENDIF}
    
    {$IFDEF HasRangeChecks}
    {$RANGECHECKS ON}
    {$ENDIF}

     

    Thanks for your reply. 

    These directives are just quoted as-is from the library on GitHub (uptodate and original) and GetIt.

     

    I haven't pulled back to get the higher level view here, having been stuck in tracing through the code to nail down the issues.

     

    FSeed is declared as Int64.  

    The function here is : function TRandom.Next(Bits: Integer): UInt32; 

    And the call is : Rnd := Next(32); 

    where Rnd is declared as Integer;

     

    I have checked that the actual bits (of course, I guess) stay the same ... but this seemingly cavalier application of (kinda) hidden casting has caused me to squint a little. 🤨 

     

    Edit

    Incorporating the corrected compiler directives, sanity is returned and FSeed can be calculated in one line again. 🎉

     

    In procedure TRandomBase64.NextBytes(var Bytes: array of Byte);  Rnd is declared as UInt64.

    With the above change, there is a Range Check Error on assigning Rnd (in TRandom.NextBytes)
    I think it is clear that Rnd should be declared as UInt32.

     

    Aaaaannnnd, on reading further down your response, I see you already concluded the same. 😅


  9. {$APPTYPE CONSOLE}
    program Project1;
    uses
      System.SysUtils, System.generics.defaults;
    
    type
      TEmp = class
         FName  : string;
         FSalary: Currency;
         FAcNo  : integer;
         function  Gett<T> (var field:T) : T;
         procedure Sett<T> (var field:T; const Value : T);
      end;
    
      function TEmp.Gett<T> (var field:T) : T;
      begin
        result := field;
      end;
    
      procedure Temp.Sett<T>(var field:T; const Value : T);
      begin
      var lComparer := TEqualityComparer<T>.Default;
          if lComparer.Equals(Value, Default(T)) then
             raise Exception.Create('Field must have a non-default value')
          else
             field := value;
      end;
    
      // credit to https://stackoverflow.com/questions/5344433/how-can-i-declare-a-pointer-based-on-a-generic-type
      // regarding Generic comparison to Default(T), and an idea of generic properties.
    
    var emp : TEmp;
        s   : currency;
        a   : integer;
    
    begin
        s   := 1000.37;
        a   := 123;
        emp := TEmp.Create;
    
        writeln('Name   : ', emp.FName );
        writeln('Salary : ', emp.FSalary:6:2 );
        writeln('Ac #   : ', emp.FAcNo );
        writeln;
    
        emp.Sett(emp.FName,  'Abc Def');
        emp.Sett(emp.FSalary, s);
        emp.Sett(emp.FAcNo,   a);
    
        writeln('Name   : ', emp.Gett(emp.FName) );
        writeln('Salary : ', emp.FSalary:6:2 );
        writeln('Ac #   : ', emp.FAcNo );
        readln;
    end.

    I was just playing around ... trying to figure out what a simple generic 'property' function could look like.
    Someone in 2009 had already been thinking down that track.
     


  10. I have been learning about RSA encryption/decryption, so I started getting to know the (Rudy Velthuis') BigNumbers project, via GetIt and D12.3.

    I started running into frustrating overflow errors (EIntOverflow) as soon as I started generating large prime numbers and doing some arithmetic with them.

     

    I ended up trying the original Github repo (https://github.com/rvelthuis/DelphiBigNumbers) and using 10.3.3, and it worked fine.
    Since then I spent quite some time to pull apart a simple line like: 

    const                                                                                                 C
      CMultiplier = UInt64(6364136223846793005);                      
      CIncrement  = UInt64(1442695040888963407);                      
    
    begin                                                              
    {$IFOPT Q+}                                                          
    {$DEFINE HasRangeChecks}                                           
    {$ENDIF}
      FSeed := Int64(FSeed * CMultiplier + CIncrement);   // << EIntOverflow
      Result:= UInt32(FSeed shr (64 - Bits)); // Use the highest bits; Lower bits have lower period.
    {$IFDEF HasRangeChecks}
    {$RANGECHECKS ON}
    {$ENDIF}
    end;

    Eventually, as a diagnostic adventure, I turned the one line into a soup of smaller steps to avoid overflow, and it works:

    //  (A.e32 + B) * (C.e32 + D) = AC.e64 + (AD+BC).e32 + BD          
                                                                       
      A     :=       FSeed shr 32;          // top 32 bits             
      C     := CMultiplier shr 32;
      B     :=       FSeed and $ffffffff;   // bottom 32 bits
      D     := CMultiplier and $ffffffff;
      BD    := B*D;
      ADBC  := A*D+B*C;
    
    //F     := ( (ADBC shl 32) + BD + CIncrement );
      f1    := BD + CIncrement;
      f2    := ADBC shl 32;
      F     := (f1 and $0fffffffffffffff) + (f2 and $0fffffffffffffff);
    
      FSeed := Int64(F);
    //FSeed := Int64(FSeed * CMultiplier + CIncrement);

    (This is inaccurate on the single most significant bit, but the algorithm says it's only using 48 bits, and has tested correctly so far)

     

    I haven't tried 10.4.2, but 11.3 and 12.3 both give the overflow error.  Is this issue known to anyone? 

     

     

     


  11. Going off your picture ... I'd say 'Yes', I think you are over-complicating things. But it is normal for us to come at a problem, trying out various ideas ... getting too close to the problem, going down dead ends, and then finally making some realisations that simplify the whole thing.

    Sometimes over and over and over - until hopefully achieving a simple and elegant solution.

    Consider just making a StringList.

    {$APPTYPE CONSOLE}
    program Project1;
    uses
      System.Classes, System.Types;
    type
          TState = (int, alpha);
    const
          Digits : set of char = ['0','1','2','3','4','5','6','7','8','9'];
    
    
    function Parse( s:String ) : TStringList;
    begin
          Result := TStringList.Create;
      var state  :  TState := int;
      var temp   :  string := '';
    
          for var ch in s do
              case state of
                int:   if ch in Digits       then temp := temp+ch
                                             else begin
                                                     if temp <> '' then result.Add(temp);
                                                     temp  := ch;
                                                     state := alpha;
                                                  end;
                alpha: if not (ch in Digits) then temp := temp+ch
                                             else begin
                                                     if temp <> '' then result.Add(temp);
                                                     temp  := ch;
                                                     state := int;
                                                  end;
    
              end;
          if temp <> '' then result.Add(temp);
    end;
    
    
    begin
      var  s:TStringList := Parse('12abcd345ghi6kl7mnopq890');
           writeln( s.Text );
           s.Free;
    
           readln;
    end.

     

    (Actually, with a StringList, all you'd really have to do is insert your chosen delimiter between runs of Alphas and Ints. But I wanted to model a bit more general approach.)

     

     

     

     

     


  12. On 12/12/2024 at 7:00 AM, 357mag said:

    Personally, I like console programming. I was wondering if there is a reason all of my books starts you off that way. Perhaps because Delphi is a clean, fairly easy to grasp language?

    There might be a marketing imperative, for new Delphi people (assuming there are some), to be able to immediately show zero-effort Windows programming, say bouncing a ball around a square ... with drag and drop components, and nice event-driven functionality.

    I think that addresses one market.

    However, I think as a programming enthusiast, coming to a new language like eg Swift, Haskell, Zig, or Odin .. or even C, C++, or Rust, then I want to understand the language itself and the expressions and idioms.

    Every time I am trying out new ideas (to me) in Delphi, or eg recently with the Advent of Code, I am writing a console program.

    I think it's the cleanest and simplest way.

    Sure there are certainly things, like events and messaging, that you will probably do with a gui program ... but yeah, I like the console.  


  13. The speed thing is addressed in the 'Behind the Scenes' video ... people who are the Olympic athletes at this event have entire solution systems pre-prepared for reading in and manipulating data, and then solving the puzzle.
    The head guy mentions that people will blast through, ignoring the text, maybe even guessing at the problem being asked in the quest for a fastest solution.

    He  specifically says that that endeavour is not "programming" as such ... it's an entirely different beast.


  14. Personally, I post everything that it takes to recreate my answer. And any sundry files (like Excel) I might employ to help along the way.

     

    Reproducible Research™ 🙂

     

    Quote

     I haven't had time yet to redo my program (nor the heart to throw away all that work--even though it's wrong).

    Ha. I feel this pain. 😅
    I have often found my code volume increasing like an expanding balloon ... until I have worked out what I should have been doing, then the cutting away begins ... and 80 lines drops back to 20.  I have this currently in my solution for Problem 5 Part 2.  60 out of 120 lines became unnecessary as I realised the information I needed to gather ... but the exploration process was necessary to come to that understanding in the first place. 🙂

    • Like 1
×