Jump to content

Marat1961

Members
  • Content Count

    74
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by Marat1961

  1. Marat1961

    Multiple two UInt64 modulo

    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. 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. Marat1961

    Multiple two UInt64 modulo

    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.
  4. Marat1961

    Multiple two UInt64 modulo

    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. Marat1961

    Having fun with Delphi

    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. Marat1961

    Having fun with Delphi

    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. Marat1961

    Having fun with Delphi

    The style of construction I saw in the book by Martin Fowler, Domain Specific Languages.
  8. Marat1961

    Having fun with Delphi

    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
  9. Marat1961

    Having fun with Delphi

    Undoubtedly a string builder must be used inside, but what a convenient and intuitive interface!
  10. Marat1961

    Having fun with Delphi

    From a usability point of view, it is desirable to store the path state inside a record. This is better than the helper in that we have a type with its own internal state. I am not a fan of using globals. The structure should look like a builder. It would be useful to add the opposite operation, parsing.
  11. Marat1961

    Having fun with Delphi

    https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/URI_syntax_diagram.svg/1602px-URI_syntax_diagram.svg.png
  12. Marat1961

    Having fun with Delphi

    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.
  13. Marat1961

    Having fun with Delphi

    // 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.
  14. The fact that the project is free, under the Apache-2.0 License. Your project should have a link to the project whose code you are using. By the way, then there was no question of mine either.
  15. 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).
  16. 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.
  17. 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);
  18. Marat1961

    Organizing enums

    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.
  19. Marat1961

    Organizing enums

    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.
  20. Marat1961

    Organizing enums

    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;
  21. Marat1961

    Organizing enums

    And what is your native language, for me it is Russian, although I am a Bashkir by nationality.
  22. Marat1961

    Organizing enums

    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.
  23. Marat1961

    Organizing enums

    That is, you so interpret the declaration of constants inside the record?
  24. How to check the zero-based index. How many comparison operations it takes to check the occurrence of a value from 0 .. Count - 1. index, fCount: Integer It would seem that it could be easier and here we write the code: Assert((index >= 0) and (index < fCount), 'Array bounds error') This is exactly the message I saw when rangecheck was on. on my very first and favorite compiler for Pascal - 1 for PDP-11. First love does not rust. This is equivalent to two checks and if you open the CPU window we can see that this is indeed the case. We use commands that take into account the upper sign bit. Oz.SGL.Test.pas.459: fCount := 5; 0066E55D C745F405000000 mov [ebp-$0c],$00000005 Oz.SGL.Test.pas.460: index := -2; 0066E564 C745F8FEFFFFFFF mov [ebp-$08],$fffffffe Oz.SGL.Test.pas.461: Assert((index >= 0) and (index < fCount), 'Array bounds error'); 0066E56B 837DF800 cmp dword ptr [ebp-$08],$00 0066E56F 7C08 jl $0066e579 0066E571 8B45F8 mov eax,[ebp-$08] 0066E574 3B45F4 cmp eax,[ebp-$0c] 0066E577 7C14 jl $0066e58d 0066E579 B9CD010000 mov ecx,$000001cd 0066E57E BABCE56600 mov edx,$0066e5bc 0066E583 B818E66600 mov eax,$0066e618 0066E588 E853C8D9FF call @Assert Some microprocessors have special commands to check the entry of the index, who can perform this check with a single command. But if you use the command of comparing unsigned numbers we can simplify the expression and write the following code Assert(Cardinal(index) < Cardinal(fCount), 'Array bounds error'); and then we can do the same check using a single comparison. This reduces the price of the check by exactly half. Oz.SGL.Test.pas.462: Assert(Cardinal(index) < Cardinal(fCount), 'Array bounds error'); 0066E58D 8B45F8 mov eax,[ebp-$08]. 0066E590 3B45F4 cmp eax,[ebp-$0c] 0066E593 7214 jb $0066e5a9 0066E595 B9CE010000 mov ecx,$000001ce 0066E59A BABCE56600 mov edx,$0066e5bc 0066E59F B818E66600 mov eax,$0066e618 0066E5A4 E837C8D9FF call @Assert Usually when debugging I try to remember to enable rangecheck. But in the release version all checks are usually turned off. That is, in training flights we fly with a parachute. But in the combat flight (in the release version) we leave this parachute at home. Then hackers use it to crack through our programs. Do not forget to check at least the input buffer of your program.
  25. Very interesting. By the way, I look at the code of your library, a lot of good ideas are used in it.
×