Jump to content

Marat1961

Members
  • Content Count

    74
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by Marat1961


  1. 32 minutes ago, julkas said:

    My initial solution has bug - we must first reduce a and b modulo m.

    Can you describe the same as an arithmetic expression? To make it clear and unambiguous.

     

    Gigo. Garbage at the input garbage at the output.


  2. On 10/23/2020 at 10:33 PM, Marat1961 said:

    Hastily sketched. Perhaps for everything to work correctly, we need to implement multiplication of 64-bit numbers.

    Since the most significant digits of the result are not used, there seems to be no difference which multiplication is signed or unsigned.

    I was tormented by vague doubts, in the end I wrote several tests and did not find any difference when performing multiplication operations for the lower digits of the result.

     

    The test code can be viewed here.
    https://en.delphipraxis.net/topic/3763-multiple-two-uint64-modulo/?tab=comments#comment-31938


  3. Why is an assembler needed for this operation?

    If the code is used for example to generate a random number.

    var seed class: Int64;
    function of the TRandom64.Def class: Int64;
    to begin
      Result: = seed * 6364136223846793005 + 1442695040888963407;
      seed: = Result;
    end;

    then we need a 2 ^ 64 remainder of the products of two Uint64 numbers.

    To do this, it is enough to multiply two numbers and take the least significant number from the result.

     

    Since the leading part of the result is not used, it seems there is no difference which multiplication works signed or unsigned.

    I was tormented by vague doubts, I wrote several tests and found no difference.

    type
      T2Uin64 = record
        hi, lo: UInt64;
      end;
    
    procedure UMul64 (a, b: UInt64; var r: T2Uin64);
    asm
      MOV RAX, a
      MUL b
      MOV r.lo, RAX
      MOV r.hi, RDX
    end;
    
    procedure TForm2.Button2Click (Sender: TObject);
    const
      imax32 = Maxint;
      imax36 = UInt64 (Maxint) * 16;
      imax63 = 9223372036854775807;
      umax64 = 18446744073709551615;
    var
      a, b, m, c, d, r1, r2: UInt64;
      r: T2Uin64;
    begin
      a: = imax63;
      b: = 2;
      d: = umax64 - 1;
      c: = a * b;
      r1: = c div m;
      r2: = (a * b) div m;
      Assert (c = d);
      UMul64 (a, b, r);
      r2: = r.lo div m;
      d: = r.lo;
      Assert (d = c);
      a: = umax64;
      b: = 2;
      d: = umax64;
      c: = a * b;
      UMul64 (a, b, r);
      b: = umax64;
      c: = a * b;
      UMul64 (umax64, umax64, r);
    end;

    If you want to find the remainder again, there is no need to use an assembler.

    // r2: = (a * b) div m;
    mov rax, [rbp + 68 $]
    imul rax, [rbp + $ 60]
    xor edx, edx
    div qword ptr [rbp + $ 58]
    mov [rbp + $ 38], rax
    

    It's better than calling an assembler subroutine anyway, because it will be faster.
    The code becomes portable and will work in both 32-bit and 64-bit implementations and on any platform.

     

    In my opinion, optimizing using assembler will only hurt here.

    • Like 1

  4. Karatsuba's algorithm is a fast multiplication algorithm.

    Karatsuba noted that in fact only three multiplications of n / 2 - digit numbers are enough, since
    (ad + bc) = (a + b) * (c + d) - ac - bd.

     

    That is, using 64/2 = 32 bit numbers, you can get a 64 bit result.

     

    N mod m where m = 2 ^ k is a power of two, you can discard bit digits more than k.
    N mod 2 ^ 32 is a 32 bit number.


  5. 3 hours ago, mvanrijnen said:

    MP2 := THSURI2.HTTPS

    A non-empty scheme component followed by a colon (:), consisting of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus (+), period (.), or hyphen (-). Although schemes are case-insensitive, the canonical form is lowercase and documents that specify schemes must do so with lowercase letters. Examples of popular schemes include http, https, ftp, mailto, file, data, and irc. URI schemes should be registered with the Internet Assigned Numbers Authority (IANA), although non-registered schemes are used in practice.

     

    If we analyze the syntax diagram, we can see that the "non-empty scheme component" and "path component" are required, which is why we included them in Init.
    A port value of 0 is reserved and means no port is specified.
    If the value can be present in the URI one time, its value will be replaced by the last usage.
    The builder is syntax-sensitive and helps to avoid errors when generating URI.


  6. 2 hours ago, mvanrijnen said:

    maybe with an TInterfaced (no need to free)

    The records do not need to be freed if there are local managed variables, the finalization code is executed before returning from the subroutine.

    // procedure _FinalizeRecord(p: Pointer; typeInfo: Pointer);
    005FD905 8D45D8           lea eax,[ebp-$28]
    005FD908 8B1530CF5F00     mov edx,[$005fcf30]
    005FD90E E829D6E0FF       call @FinalizeRecord
    005FD913 C3               ret 

     


  7. unit Uri;
    
    interface
    
    uses
      System.SysUtils;
    
    type
      PxUri = ^TxUri;
      TxUri = record
      private
        FScheme: string;
        FPort: Cardinal;
        FHost: string;
        FUserName: string;
        FPassword: string;
        FPath: string;
        FQuery: string;
        FFragment: string;
      public
        function Init(const Scheme, Path: string; Port: Cardinal = 0): PxUri;
        function Host(const Value: string): PxUri;
        function UserName(const Value: string): PxUri;
        function Password(const Value: string): PxUri;
        function Path(const Value: string): PxUri;
        function Query(const Value: string): PxUri;
        function Fragment(const Value: string): PxUri;
        function ToString: string;
      end;
    
    implementation
    
    function TxUri.Init(const Scheme, Path: string; Port: Cardinal): PxUri;
    begin
      Result := @Self;
      Self := Default(TxUri);
      FScheme := Scheme;
      FPath := '/' + Path;
      FPort := Port;
    end;
    
    function TxUri.Host(const Value: string): PxUri;
    begin
      Result := @Self;
      FHost := Value;
    end;
    
    function TxUri.UserName(const Value: string): PxUri;
    begin
      Result := @Self;
      FUserName := Value;
    end;
    
    function TxUri.Password(const Value: string): PxUri;
    begin
      Result := @Self;
      FPassword := Value;
    end;
    
    function TxUri.Path(const Value: string): PxUri;
    begin
      Result := @Self;
      FPath := FPath + Format('/%s', [Value]);
    end;
    
    function TxUri.Query(const Value: string): PxUri;
    begin
      Result := @Self;
      if FQuery = '' then
        FQuery := Format('?%s', [Value])
      else
        FQuery := FQuery + Format('&%s', [Value]);
    end;
    
    function TxUri.Fragment(const Value: string): PxUri;
    begin
      Result := @Self;
      FFragment := Format('#%s', [Value]);
    end;
    
    function TxUri.ToString: string;
    var
      sb: TStringBuilder;
    begin
      sb := TStringBuilder.Create;
      try
        sb.Append(FScheme); sb.Append(':');
        if FHost <> '' then
        begin
          sb.Append('//');
          if FUserName <> '' then
            sb.AppendFormat('%s:%s@', [FUserName, FPassword]);
          sb.Append(FHost);
          if FPort <> 0 then
            sb.AppendFormat(':%d', [FPort]);
        end;
        sb.Append(FPath);
        if FQuery <> '' then
          sb.Append(FQuery);
        if FFragment <> '' then
          sb.Append(FFragment);
        Result := sb.ToString;
      finally
        sb.Free;
      end;
    end;
    
    end.
    procedure TForm2.Button1Click(Sender: TObject);
    var
      uri: TxUri;
    begin
      uri.Init('http', 'Mammalia', 8080)
         .UserName('yourname')
         .Password('TopSecret')
         .Host('www.website.com')
         .Path('Theria')
         .Path('Carnivora')
         .Path('Felidae')
         .Path('Lynx_pardinus')
         .Query('showall')
         .Query('yearstart=1990')
         .Fragment('StartReadingHere');
      Label1.Caption := uri.ToString;
    end;

    http://yourname:TopSecret@www.website.com:8080/Mammalia/Theria/Carnivora/Felidae/Lynx_pardinus?showall&yearstart=1990#StartReadingHere


     

    005FD859 68901F0000       push $00001f90
    005FD85E 8D45D8           lea eax,[ebp-$28]
    005FD861 B92CD95F00       mov ecx,$005fd92c
    005FD866 BA4CD95F00       mov edx,$005fd94c
    005FD86B E8C8F8FFFF       call TxUri.Init
    005FD870 BA64D95F00       mov edx,$005fd964
    005FD875 E856F9FFFF       call TxUri.UserName
    005FD87A BA84D95F00       mov edx,$005fd984
    005FD87F E874F9FFFF       call TxUri.Password
    005FD884 BAA4D95F00       mov edx,$005fd9a4
    005FD889 E81AF9FFFF       call TxUri.Host
    005FD88E BAD0D95F00       mov edx,$005fd9d0
    005FD893 E888F9FFFF       call TxUri.Path
    005FD898 BAECD95F00       mov edx,$005fd9ec
    005FD89D E87EF9FFFF       call TxUri.Path
    005FD8A2 BA0CDA5F00       mov edx,$005fda0c
    005FD8A7 E874F9FFFF       call TxUri.Path
    005FD8AC BA28DA5F00       mov edx,$005fda28
    005FD8B1 E86AF9FFFF       call TxUri.Path
    005FD8B6 BA50DA5F00       mov edx,$005fda50
    005FD8BB E8ECF9FFFF       call TxUri.Query
    005FD8C0 BA6CDA5F00       mov edx,$005fda6c
    005FD8C5 E8E2F9FFFF       call TxUri.Query
    005FD8CA BA98DA5F00       mov edx,$005fda98
    005FD8CF E8B8FAFFFF       call TxUri.Fragment
    TestUri.pas.42: Label1.Caption := uri.ToString;
    005FD8D4 8D55D4           lea edx,[ebp-$2c]
    005FD8D7 8D45D8           lea eax,[ebp-$28]
    005FD8DA E835FBFFFF       call TxUri.ToString
    005FD8DF 8B55D4           mov edx,[ebp-$2c]
    005FD8E2 8B45FC           mov eax,[ebp-$04]
    005FD8E5 8B80D4030000     mov eax,[eax+$000003d4]
    005FD8EB E8F446F4FF       call TControl.SetText

     

    • Like 3

  8. There must be a vision, ideas why this project is needed?
    Do you need to define the goals of the project and understand whether it is worth initiating such a project?
    Otherwise, an error may occur when starting the project.
    Wasted time on questionable jobs.

     

    I see the point of doing something if there is support:
     - different platforms (window, unix, ...);
     - rigid data typing
      (is it easy to confuse this type with any other string);
    - device concepts;
    -  relative path;
    - absolute path (starting from the root directory);
    - transformation of presentation from one platform to another;
    - converting a relative path to an absolute one and vice versa.



  9.  

      // Conversion functions (return an empty path on error)
      TxPath = record
      const
        SEPARATOR = {$IFDEF MSWINDOWS} '/'; {$ELSE} '\'; {$ENDIF}
      var
        raw: string;
      public
        constructor From(const raw: string);
        class function CurrentDirectory: TxPath; static;
        procedure Clear;
    
        function Equals(const other: TxPath): Boolean;
        function IsEmpty: Boolean;
        function IsAbsolute: Boolean;
        function HasExtension(const ext: string): Boolean;
        function FileName: string;
        function FileStem: string;
        function Extension: string;
    
        function WithExtension(const ext: string): TxPath;
        function Parent: TxPath;
        function Join(const component: string): TxPath; overload;
        function Join(other: TxPath): TxPath; overload;
        function Expand(fromCurrentDirectory: Boolean = False): TxPath;
        function RelativeTo(base: TxPath): TxPath;
    
        // Conversions to and from platform independent representation (usually Unix)
        class function FromPortable(const repr: string): TxPath; static;
        function ToPortable: string;
      end;

    In my opinion, at this stage it is to reinvent the wheel again.
    Although sometimes there is a desire for it to be a separate entity.
    There is a System.IOUtils module that provides the required set of functionality.
     


  10. 1 hour ago, julkas said:

    Here is my SplitMix64.

    I think it's good starting point.

    Why did you decide this code is a good pseudo-random sequence generator?

    What is his period?
    What are its statistical parameters?
    What tests were performed to assess quality?

     

    By the way, I'm wondering for what purpose exactly a 64-bit pseudo-random sequence generator was required?

    It would be helpful to know the domain of application (DDD).


  11. Maybe you are satisfied with the implementation of a pseudo-random sequence generator for a 64-bit integer using the Linear congruential generator method.

    I used the coefficients for the generator recommended by Donald Knuth in his book.

     

    Hastily sketched. Perhaps for everything to work correctly, we need to implement multiplication of 64-bit numbers.

     

    class var 
      seed: Int64;
    
      
    class function TRandom64.Def: Int64;
    begin
      Result := seed * 6364136223846793005 + 1442695040888963407;
      seed := Result;
    end;
    

     

    Project https://github.com/marat1961/Tower-of-Babel.


  12. In the process of development on the level of the subject area you want to see the problem at the moment of its occurrence.
    Memory destruction from outside the array may be detected too late.

     

    In complicated cases, it may take several hours of your life to find such an error.
    Do you need to optimize your program?
    And if necessary, for the program code more than adhere to the principle of Pareto 80/20 (here you probably need to amplify by 10 times) 98% of the time takes 2% of the code.

    You need to optimize this 2%, and even if it is critical for you.

     

    Even when I was programming microprocessors where the average execution time of one instruction was 3-10 µs LSI-11 and only 8-16k memory I was not saving on safety.

     

    I programmed in Pascal with all the checks included.

    And yet my program code was more functional and faster than the programs of my colleagues who programmed on Assembler.

    I usually had a better program due to better Pascal code control.

    When I was still young and green, immediately after graduating from the Radio Engineering Department of the university, with no specialized training in programming, I tried to detect a repeating code and to extract it to a parameterized subprogram.
    I had my favorite book, "Algorithms and Data Structures", by Niklaus Wirth, Mir Publishing House, 1985

    which is always next to me, although it already has a double glued cover and some pages are already scattered from use.

     

    If my developed algorithm will work correctly for data in some value domain, I will add a check of this condition.

     

    Unlike some of my colleagues who honor my uniform and think that the appearance of an error message is a bad tone.

    Some of them do not show any errors or even close the error output.


    I know what the mistake is and exactly where it happened. 
    I will also try to react quickly and preferably close the problem by the evening and post an extraordinary release.
    As a result, I don't have problems with my programs' support for a long time already.
    As a result of this approach, I am mainly engaged in extending the functionality of my programs, rather than closing holes in them.

     

    Rarely is 100% code coverage by tests in real projects.
    And even 100% code coverage by tests does not guarantee absence of errors in the code.
    If the logic is complex, there is no guarantee that every variant of a passing branch has been tested.
    A test can detect an error, but tests do not guarantee that there are no errors in code.

     

    In principle, an effectively implemented iterator could provide a fast and safety iteration of array elements.
    For me it would be best if the iterator returned the element address.
    it is possible to check the fields of the element and change something in it if necessary.

     

    The fastest way to search is with sentinel, when we only compare values and do not check the element index.

    To do this we add sentinel to the list at the end of the list and set the key value in sentinel.

    p := List.First;
    List.Sentinel.Key := x; 
    while p.key <> x do Inc(p, Itemsize);
    if p <> List.Sentinel then ...

     

    At the end of the list we check which element we have reached if it means that the sentinel is not looking for it.
    The structures with sentinel are not only a list.

     

    The current version of the Delphi iterator is not quite perfect,
    it requires the call of two methods.
    It would be better if the iterator or list executed the code until it said "I did what I wanted".

    DoSomething: TEnumFunc;
    list.Enumerate(DoSomething);


     

    • Like 1

  13. I use enumerated types a lot, there is nothing wrong with them.

    If you have an enumerated type parameter in a procedure, the compiler will not give you another substitution, unlike integer constants that can be confused.

     

    However, no one bothers to use handlers instead of integer constants. This is usually an record with a number or
    a packed record with a set of Subrange Types fields that can take up a comparable amount of memory.
    By the way, I caught myself thinking, I have not experimented with packed records with enumerated fields.

     

    In the handler, some of the bits can be set aside to determine the type, subtype, number of the object within this subtype.

    Something like a decimal classifier, like the medical classifier of diseases.

    I was the architect of the openEHR-based medical information system for the Tomsk Scientific Research Institute of Cardiology.

    Such classifiers are ubiquitous in various databases and reference information systems.


  14. On 10/15/2020 at 2:16 PM, Rollo62 said:

    I'm not 100% sure, since I never checked that, but I think class helpers won't work on consts.

    I hope we are not talking about writing a helper to any specific value of the enumerated type?
    Besides the declaration of constants, you can declare other related types for these constants, as well as methods to work with them.
    Helpers for record can also be written.

      hEntity = record
        v: Cardinal;
      end;
    
      hEntityHelper = record Helper for hEntity
        constructor From (v: Cardinal);
        function FromRequest: Boolean; inline;
        function Request: hRequest; inline;
      end;
    
      TsdEntity = record
      const
        NoEntity: hEntity = (v: 0);

    It would be possible to write methods directly in the type itself, but in our case there was a mutual dependence of handlers for several types. Helpers allowed to solve this problem in a graceful way.
    Unlike the classes, I cannot write a forward declaration for writing. But at least I can declare pointers to a record which will be declared later, either in the interface part or in the implementation section.


  15. 21 hours ago, Stefan Glienke said:

    If that would compile - and even if it would that would not prevent that set to be assigned [4] to.

    Validation works for the range type, but this check fails for the set.

    Enum set in Delphi is also not implemented perfect.

    I've seen better and more correct implementations of the Pascal language.

     

    procedure TestTsgList.Test1;
    type
      TRange = 0..15;
      TSet = set of TRange;
      TMyEnum = (Neg = 1, Template = 4, Static = 15, Header = 2, Custom = 4);
      TMyEnumSet = set of TMyEnum;
    var
      i, size: Integer;
      r: TRange;
      s: TSet;
      e: TMyEnum;
      es: TMyEnumSet;
    begin
      size := sizeof(es);
      size := sizeof(s);
      // set of enum
      es := [TMyEnum(3), TMyEnum(10)];
      e := High(TMyEnum);
      e := Succ(e);
      Include(es, e);
      Include(es, TMyEnum(10));
      // set of range
      r := 15;
      r := Succ(r);
      Include(s, r);
    end;

     


  16. 18 hours ago, Kryvich said:

    Members of an enum are not objects. For ex. I have IDs of syntax relations of words in a natural language (about 200 IDs). The numerical values of the enumeration members are not important to us, only their names matter. Therefore, there is no need to specify integer values for each member of an enum in your program.

    I am not forcing you to use this programming style.
    In my programs at the domain level, I also make extensive use of enumerated types.
    I consider it permissible to use them even in the library if it is available in the source.
    But knowing the pitfalls of using them is probably not bad.

    Niklaus Wirth for me is a GURU of the highest level

     

    I would have already thought about their organization and semantic separation.
    It is possible that these names should be organized into some taxnomy, and maybe even more than one.

    And what kind of subject area, knowledge base?
    May I have a look at the code of your project?
    Type declarations and how you use them.

     


  17. 55 minutes ago, Kryvich said:

    I use enums with 100 or more members. If instead of them I used named integer constants, adding and subtracting them, there would be many hard-to-find errors.

    I remember where I had to use an enumerated type of this size.
    Probably the largest type is tokens in the parser.
    But now I use the compiler of the compiler.

    In my opinion, when there are a lot of objects, they no longer work by name. The head and brains do not need to be overloaded.

    For identification, you already need to use handlers.
    So that there is no desire to cope with them, you can put the whole in the record.

       hParam = record
         v: Cardinal;
       end;
       hParamHelper = record Helper for hParam
         constructor From (v: Cardinal);
         function request: hRequest; inline;
       end;

    or they write well here
    http://gamesfromwithin.com/managing-data-relationships

×