Jump to content

dummzeuch

Members
  • Content Count

    2634
  • Joined

  • Last visited

  • Days Won

    91

Everything posted by dummzeuch

  1. Fixed the string order issue.
  2. Here are some timings: sorted reverse half random QuicksortInteger(1000000): 0.05787 0.06269 not done 0.16328 QuickSortPlusInteger(15)(1000000): 0.04744 0.04995 0.24928 0.14548 TimSortInteger(1000000): 0.00214 0.00252 0.00981 0.16411 QuicksortString(1000000): 1.36692 1.00144 not done 1.16640 QuickSortPlusString(15)(1000000): 1.38534 0.99298 0.81605 1.23809 TimSortString(1000000): 0.06285 0.09036 0.16268 1.86726 Sorting 1 million integers or strings respectively. The strings are simply generated with IntToStr for numbers 0 to 999,999 and compared with CompareStr. This means that Sorted, Reverse and half for strings is not really correct, because '10' < '2' etc. I need to fix that, but this is not too bad a dataset for sorting tests either. (I just googled and found that apparently there are some test datasets for sorting algorithm performance. I'll have a look into that.) The numbers are the time in seconds for a single run on my computer. As you can see, TimSort is faster than all of them with the exception of random data, where it is still in the same ballpark. The test program is in the subdirectory Tests\SortingTests. Please note that with the exception of TimSort, these sorting algoritmms are not implemented for best performance but for convenience: They are abstracted from the data and use callbacks to compare and swap items. TimSort currently works directly on the data and uses a callback only for comparison, but my goal is to abstract the algorithm from the data in a similar manner, if possible.
  3. My implementation now uses Pseudo Templates based on include files (please note that the linked article is ancient, so take its C++ references with a grain of salt), so it should be compatible with most Delphi versions (tested with Delphi 2007 and 10.2). The source is on OSDN in my dzlib. It has been tested with sorting dynamic arrays of integers and strings, but should work with anything else that does not include reference counting (so no interfaces yet). It's much slower for strings because of the special code in the MoveItems method which allows for reference counting (for strings, should also ). Unit tests are in the UnitTests\SortingTest subdirectory of dzlib. The units declaring TimSort for Integer and String arrays use the above mentioned template. To get the source, use SubVersion to create a working copy from http://svn.osdn.net/svnroot/dzlib-tools/dzlib/trunk
  4. The following code looks innocuous but slows down a program significantly: type TJCHListSortCompare = function(Item1, Item2: Integer): Integer of object; TCheckListBoxWithHints = class(TCheckListBox) private procedure QuickSort(L, R: Integer; SCompare: TJCHListSortCompare); // [...] procedure TCheckListBoxWithHints.QuickSort(L, R: Integer; SCompare: TJCHListSortCompare); var I, J, P: Integer; tmpObj: TObject; tmpStr: string; tmpChecked: Boolean; begin repeat I := L; J := R; P := (L + R) shr 1; repeat while SCompare(I, P) < 0 do Inc(I); while SCompare(J, P) > 0 do Dec(J); if I <= J then begin // exchange I and J tmpStr := Items[I]; tmpObj := Items.Objects[I]; tmpChecked := Self.Checked[I]; Items[I] := Items[J]; Items.Objects[I] := Items.Objects[J]; Self.Checked[I] := Self.Checked[J]; Items[J] := tmpStr; Items.Objects[J] := tmpObj; Self.Checked[J] := tmpChecked; if P = I then P := J else if P = J then P := I; Inc(I); Dec(J); end; until I > J; if L < J then QuickSort(L, J, SCompare); L := I; until I >= R; end; Yes it’s Quicksort and it sorts strings in a TCheckListBox’s Items property, swapping not only the strings but also the objects and the Checked values. Now, run this with, lets say 100 entries. That shouldn’t be any problem for Quicksort, should it? But it takes about 2 seconds on my computer which is muuuuuuch longer than I expected. The same code running on a simple TStringList takes less than 1/10 of a second. Why is that? read on in the blog post
  5. BeginUpdate / EndUpdate didn't make any noticeable difference in my tests. Otherwise I wouldn't have bothered to make any of the other changes.
  6. How often do you access the ScanLine property? I found that it is much faster to get the address of the first line, calculate the offset between lines and add (or subtract) the offset to get the other lines. Also, pointer incrementation is much faster than using an array with indexes. On top of that, make sure to disable range checking in the release code. There is some code that does it in u_dzGraphicsUtils in my dzlib. If I remember correctly I blogged about it too. Edit: Yes I did: https://blog.dummzeuch.de/2019/12/12/accessing-bitmap-pixels-with-less-scanline-calls-in-delphi/
  7. dummzeuch

    Customizing source editor

    I think that's a side effect of fixes for this problem: https://stackoverflow.com/questions/25295980/delphi-2006-2010-error-cannot-create-file-c-users-admin-appdata-local-temp-ed E.g. if you are using my dzeditorlineendsfix tool. It prevents the font file used by the editor for the line ends to be loaded. Since that is only necessary for Delphi 2006 to 2010 you may not need it any more.
  8. dummzeuch

    Customizing source editor

    I usually turn on "Show tab characters" (source options) and "BRIEF cursor shapes" (display). I also change "Right Margin" to 100. And today I turned off Italic for comments, thanks for that hint.
  9. My sorting functions aren't optimized for speed but for convenience. They take function pointers for comparing and swapping two elements rather than directly working on the data. That's a considerable overhead. My current TimSort doesn't do that yet and I'm not sure whether it will be possible to implement it in such a way, but I will try it.
  10. I just read the Apache License (never did before) and have now added a link to the source code above. Note that the current code can only sort an array of integer and is pretty rough. I'll clean it up a bit today and add more tests. I also started a new thread on this: TimSort for Delphi without Generics.
  11. dummzeuch

    simple cloud storage options

    The simplest way i can think of is a hosted web server that supports https for your clients (add some kind of logon if you need it) and uses sftp to upload files.
  12. Impressive: sorted reverse half random QuickSort(10000000): 0.69550 0.72872 not done 1.89622 QuickSort+(12)(10000000): 0.63999 0.65609 3.61170 1.70513 QuickSort+(15)(10000000): 0.63134 0.66484 3.65941 1.72658 QuickSort+(17)(10000000): 0.63200 0.65742 3.58655 1.73312 QuickSort+(20)(10000000): 0.59678 0.62114 3.60640 1.75100 TimSort(10000000): 0.02052 0.03282 0.11939 1.88033 QuickSort(100000000): 8.13450 8.50642 not done 21.52633 QuickSort+(12)(100000000): 7.16910 7.47369 45.95549 19.66967 QuickSort+(15)(100000000): 7.25634 7.49350 45.59182 19.57720 QuickSort+(17)(100000000): 7.15293 7.43410 46.06242 19.69688 QuickSort+(20)(100000000): 7.26109 7.46288 46.09772 20.61769 TimSort(100000000): 0.20487 0.33015 1.12082 23.05309 This is the result of a test sorting an array of 10 Million and 100 milliion integers on my computer. The values are the time in seconds. QuickSort is my regular quicksort implementation QuickSort+ is my optimized quicksort which: choses a pivot by selecting the median between elements Left, Right and (Left + Right) / 2 uses InsertionSort for small sets, if Right - Left < Cutoff (The value in parenthesis is the cutoff.) TimSort is the code from the link above, adjusted so it compiles with Delphi 2007 (no generics). Edit: Here is the source code. Note that It currently can only sort an array of integer.
  13. Don't know whether it's any good, but here is one for free pascal: https://github.com/avk959/LGenerics Unit lgMiscUtils
  14. A ListView would also require lots of messages, but from experience i know that it can easily handle thousands of lines and still be reasonable fast (we're talking about less than 200 here). A VirtualTreeview would be an option, but meaning to add yet another component which i am rather reluctant to do in this case. Another option would be a (virtual) StringGrid, I actually started down that road but decided to try and improve that sorting first. Now I've got a solution that's fast enough and works, so I'll probably leave it as is.
  15. As I said: A virtual ChecklistBox would have been ideal, but unfortunately that mode has been broken since forever. So it's either live with that, or use a different control (ListView?). I'm still considering the latter, but I'm not sure it's worth the effort since it's fast enough now and newer IDEs already come with a similar functionality.
  16. Hm, good point, I'll have to check that too. Edit: No, doesn't happen.
  17. Yes @Anders Melander, you are right in all points. Unfortunately none of the options you mention was possible in this case (Delphi 6 -> no Generics, Objects already used). I could also have used TStringList.Objects to store the old index and use Sort, just as you describe for TList<integer>, but that wouldn't have helped much in this particular case. The point of this post was that everything else is better than directly using the Items property and that it is not obvious why. A virtual CheckListBox would have been even better, but that code is broken since like forever.
  18. I think you meant "worse" here.
  19. This should do the trick: function GetSetCardinality(const aSet; aLen: Word): Word; var B, i: Integer; abyte: PByte; begin Result := 0; abyte := @aSet; for B := 0 to aLen - 1 do begin for i := 0 to 7 do if (abyte^ and (1 shl i)) <> 0 then Inc(Result); Inc(abyte); end; end; test code: var SomeSet: set of 0..255; Count: Word; begin SomeSet := [1, 5, 6, 100, 200]; Count := GetSetCardinality(SomeSet, SizeOf(SomeSet)); Count should be set to 5, the number if elements in the set. ALen should be 32. var SomeSet: set of 0..10; Count: Word; begin SomeSet := [1, 5, 6]; Count := GetSetCardinality(SomeSet, SizeOf(SomeSet)); Count should be set to 3, ALen should be 2 (one byte has 8 bits, the set can have 11 elements (0..11) which is > 8 and <= 16 -> 2 bytes.
  20. Even worse: It provides a false sense of security and on top of that results in a runtime error that isn't really an error in this case. On the other hand, there is the aLength parameter which supposedly contains the length of the aSet parameter in bytes and there is nothing to prevent it from being larger than Length(bytes) (Assuming that aSet is a set as the name implies it has a maximum size of 32 bytes = 256 elements, each represented by one bit). Using a PByte would probably be better here and some comment would also be in order.
  21. dummzeuch

    Are Valid Dates?

    Why are these dates stored as strings in the first place? If they are in a database they should be in a date field. If they were entered with a date picker, they should be TDate or TDateTime variables. If you want to store them as strings in a database for whatever reason, store them in a standard format: ISO 8601, and document that format. Don't rely on your users having Windows configured for any particular date format, you will find somebody who didn't, especially if your program is used in more than one country. And keep in mind, that date formats can be ambiguous: 01/12/15 can be 12 January 1915 or 12 January 2015 (American format), 1 December 2015 (British format), 15 December 2001 (some MSSQL format that looks like they got ISO 8601 wing). The only one I haven't seen so far is using the middle term for the year, but I'm sure some idiot will come up with that too. TryStringToDate by default uses the Windows settings, so that's out in this case. I wrote my own conversion and checking code for ISO 8601. It's in my dzlib if you are interested.
  22. dummzeuch

    Can an app beat a spreadsheet?

    Just remembered capecod gunny (Michael Riley) who wrote some financial software in Delphi. Not sure whether it can apply here because it seem very specific to - in my view - typical American problems. https://www.zilchworks.com/zilch-standard.asp
  23. dummzeuch

    Can an app beat a spreadsheet?

    Excel is a nice tool for simple everyday tasks. It becomes a support nightmare once it somehow gets involved in the business procedures, because of course everybody thinks he is an expert in Excel and knows exactly how to use it and how to change stuff. Sooner or later you will end up with a monster spreadsheet that nobody can understand. As to the topic: Either people know how to use spreadsheets, then they will probably already use it for that task, or they don't, in which case they most likely will be overwhelmed when you give them anything more than a table with a few sums. Will they pay you for support? By the hour? If not, don't use Excel. You will end up either spending a lot of unpaid time for support or they will hate you, because you don't.
  24. dummzeuch

    PlasticSCM, Delphi, Semantic merge

    The current version doesn't work with Delphi (as reported in that project and in the SemanticMerge forums). I fixed that issue a while ago, but by now even that fix might no longer work: https://github.com/dummzeuch/pas2yaml But I don't use it (I only tried it for a while), so I don't really care.
  25. I think you are, because a different monitor resolution won't change anything for the position or size of a control. Only different pixel densities will, but these properties won't help there either. But whatever the reason for these properties, they are an annoyance and not useful for most people.
×