zapshe wrote: |
---|
Again, who's the target audience for those rules? Professional algorithm analysists or the practical programmer? |
Both.
zapshe wrote: |
---|
It makes sense not to fret over base 10 or base 2 as an analyst, not so much when you're expected to shave off every possible ms of runtime. |
Time complexities can be helpful to understand certain high-level aspects of the performance,
but for low-level optimizations that doesn't improve the time complexities it becomes more a matter of understanding and experience, having a feeling for what is more efficient, and to benchmark and test that it actually is an improvement (this is harder than it sounds).
zapshe wrote: |
---|
As already noted already, the Big-O of an algorithm can only tell you that from x to infinity, it will outperform any other algorithm with a worse time complexity. |
Yes, exactly. This is still useful information.
Usually it is better to go with the algorithm that has the better time complexity. If you know that another algorithm tend to perform better for your particular situation (from experience or because you have measured) then by all means use that one instead, but if you write code that should be able to handle an unknown number of elements it's usually safer to pick the one that has better time complexity.
zapshe wrote: |
---|
If you have O(n) vs O(log(n)), how can you tell at which n value O(log(n)) starts to outperform O(n)? You have no idea. |
If I have no other information I would guess the O(log(n)) algorithm is faster. If I know n is
always small I might want test to make sure, but because n is small it might not have a big impact on the overall performance so I might not bother to test it after all.
zapshe wrote: |
---|
For the practical programmer, showing O(10n) vs O(100*log(n)) will give a better idea - you can deduce what x is. |
To me this does not add any information. If I really wanted to check if the O(n) algorithm is faster for my particular use case I would test it.
zapshe wrote: |
---|
You'd understand that sorting algorithms tend to do extra work in the short run to save time in the long run AND you'd be able to deduce at what n value you'll start seeing the benefits of the extra short term work. |
Is the number of elements small? Are they nearly sorted? Do you care more about the worst case or the average case?
There are a lot of things to consider when implementing a general-purpose sorting algorithm that will be used in a lot of different situations. I've heard that std::sort is often implemented as a hybrid between different sorting algorithms.
Under certain circumstances there might be better algorithms. For sorted or nearly sorted elements insertion sort (or even bubble sort) can often outperform more sophisticated algorithms.
Peter87 wrote: |
---|
I mean, what are you even counting? |
You mean
loop iterations?
Does that mean you would describe an algorithm that loops over all elements once and calls f() and g() on each element as
O(n)
1 2 3 4 5
|
for (auto& e : vec)
{
e.f();
e.g();
}
|
and an algorithm that uses two loops, one that calls f() and another one that calls g(), as
O(2n)?
1 2 3 4 5 6 7 8 9
|
for (auto& e : vec)
{
e.f();
}
for (auto& e : vec)
{
e.g();
}
|
My concern is whether 2 is actually a meaningful value. Sure the second algorithm uses two loops and will therefore probably have to pay for the loop overhead twice but is it doing twice as much work? Maybe, but probably not.
Maybe f() and g() are very expensive functions that makes the loop overhead vanishingly small in comparison.
Maybe using two separate loops is better because it allows the compiler (or the person that implements it) to use SIMD instructions to process multiple elements at the same time.
If I added a lot of additional code (that runs in constant time) to each iteration that wouldn't change the value of the constants despite that each iteration then could take 2 or 3 times as long to run.
So to me that number 2 seems very arbitrary and not useful.
zapshe wrote: |
---|
A O(log(n)) algorithm CAN take longer than an O(n) one, [...], hence why you can't use Big-O as a replacement for timing your program. |
Yes, for sufficiently small n that could indeed be true. I have never claimed otherwise.
zapshe wrote: |
---|
But why deliberately remove information to meet the standards of Big-O notation ... |
Because it's not meaningful information? The "information" (about the constants) is gone as soon as you write it inside
O( here ).
What you're trying to do is redefine what Big O means. It's like saying 10/15 has more information than 2/3. I guess in some context it
does but in that case / doesn't really mean "divided by". It instead means "out of" (ten out of fifteen). While you of course
could do something similar here with Big O it would be confusing for no good reason.
zapshe wrote: |
---|
... when you're programming for yourself and not to study algorithms? |
To me there is no real difference between the two. Programs can be thought of as algorithms. Big O should still work the same way.
zapshe wrote: |
---|
I'm not sure we're even disagreeing. Perhaps you simply respect the notion of Big-O more as a scientific measurement rather than a practical one. |
I think it
is practical. It's only a problem if you're trying to interpret it to mean things that it doesn't mean.
I admit to having taken "algorithms" courses in the past and while I'm no expert on the subject and having forgot a lot of things I still try to follow the academic/computer science definition of what Big O means because that is the only thing that makes sense to me. To my recollection, it's the first time I see an alternative definition of Big O being proposed, although I have seen plenty of misconceptions in the past.
zapshe wrote: |
---|
Did my Big-O with benefits joke land? :( |
As a non-native English speaker I'm afraid I've only heard the expression "with benefits" but don't fully comprehend its comedian value. I did understand it was not totally serious though, especial since you used that smiley. :-)