News for hackers. Stuff that matters.
Re:O(N^2) in CreateProcess by magicalhippo on Monday April 22, 2019 @06:55AM (#19717878)
One thing I really miss in a lot of library documentation is performance guarantees similar to that of the C++ standard library.

Yes yes, this method lets me find the index of an element, but is it O(log N) or O(N)? I need to know, otherwise I might inadvertently create O(N^2) code.

Re:O(N^2) in CreateProcess by bjoli on Monday April 22, 2019 @02:12PM (#19721199)
Scheme requests for implementation often have this specified, soo for example https://srfi.schemers.org/srfi-140/srfi-140.html

It specifies it for every procedure (the preface says that procedures that don't specify asymptotic performance run in O(n).

Re:O(N^2) in CreateProcess by JoeAltmaier on Monday April 22, 2019 @02:18PM (#19721272)
I'd like a lot more than that! Including memory promises (who frees associated buffers/handles), critical-sections involved in the call, and where it can be called from (user space? kernel? interrupt routine/driver? callback? hyperthread affinity?)
Re:O(N^2) in CreateProcess by consp on Monday April 22, 2019 @09:05AM (#19718577)
I'm more interested in the lower, "average" (random input), sequential and empty set bounds as they tend get close, in certain instances (e.g. large memory space required, only efficient on ordered data etc), to the upper bound. If your algorithm for function is O(n^2) in theory but has an lower average bound of O(N log N) which almost always is used on your input data, it might be a good thing to sanitize the input and use it anyways (looking at you quicksort).
Re:O(N^2) in CreateProcess by scott_s on Monday April 22, 2019 @11:30AM (#19719660)
To put names to what you're asking for: best-case, average-case and worst-case analysis. All are valid ways to characterize algorithms.
Re:O(N^2) in CreateProcess by kadoban on Monday April 22, 2019 @01:14PM (#19720657)
Average-case can be quite an odd beast. You have to be careful what you are averaging over -- what distribution you're assuming in the analysis.

For example for quicksort, if you implement it such that it always pivots on the first element of the range to be sorted, that could be average-case O(n lg n) if I consider all possible orderings of the inputs of the given size, but if I usually call it with an almost sorted array, that's not the average behavior I'm going to see by any means.

So in most cases it ends up being a pretty leaky and dangerous contract that your function is providing, with average-case analysis. You have to know deep details of how it's working.

An often better way to go, when it's possible, is to use expected-time. So again using quicksort as an example, this would mean the algorithm randomly chooses a pivot in the given range. The difference now is, the worst-case is still O(n^2), but there's no input I can give it (accidentally or intentionally) that will trigger that behavior, I'd have to get insanely unlucky for that to happen on a large input.

Re:O(N^2) in CreateProcess by scott_s on Monday April 22, 2019 @01:40PM (#19720899)
I almost made the same point, but I stopped because I was hesitant to get into the cases where one can do an average-case analysis without assuming any distributions: when you're doing analysis of a particular operation being called a bunch of times, versus once. In such cases, average-case can yield amortized analysis which still makes no assumption of the input distribution.

I'm co-author on a paper which does that: https://www.scott-a-s.com/files/debs2017_daba.pdf. In that work, we present a sliding window aggregation algorithm for worst-case constant time, but we compare against ones that are average-case constant time. The average-case constant algorithms are better on throughput, but worst-case constant is better on latency.

Re:O(N^2) in CreateProcess by rightbyte on Monday April 22, 2019 @08:10AM (#19718246)
Yes that would be nice but the O(...) notation is not very useful for choosing algorithms unless you also compare how eg. a O(n) algorithm compares to a O(n^2) given a certain amount of nodes to compute.
Re:O(N^2) in CreateProcess by fluffything on Monday April 22, 2019 @08:55AM (#19718508)
Complexity bounds do not answer the question of how fast an algorithm or a particular implementation of it is. I don't think anybody claimed that, and that was actually not the problem here.

The problem here is that the implementation exploded when passed an input Nx larger in production than what the implementation was tested with. Complexity bounds would have prevented that problem because "maybe process creating shouldn't be O(N^2)".

So sure, choose an O(N^2) algorithm if its faster than an O(N) one for small enough N, there is nothing wrong with that. But don't do that if the size of the input does not depend on you (or fall back to a O(N) algo for very large inputs).

People doing this is why DDoS are a thing: my O(N^3) server was very fast for 100 connections, who would have thought that someone would DDoS it with 1000 connections - yeah, who would have thought about that, 1000 connections isn't even a real DoS, but whatever.

Re:O(N^2) in CreateProcess by rightbyte on Monday April 22, 2019 @09:35AM (#19718775)
Yes I agree.

What I think is misleading about the general use of O() by programmers is that it is an theoretical construct and other discountineous effects like cache misses (cache size) etc is not taken into consideration and further more the range of n:s for which each algorithm is fastest is often ignored.

Some dummy numbers:

T1 = 0.0000001 n^2 + n

T2 = 100000000 n

Would yield: O1(n^2) O2(n)

Long before n is big enough for a hypothetical server running the O(n^2) algorithm to be slower than the O(n) other effects might cap it.

The best way to find out is empirical testing.

Re:O(N^2) in CreateProcess by jnurmine on Monday April 22, 2019 @02:58PM (#19721738)
Isn't the point the order of growth...? If you double the input size, O(N) will run twice as long, whereas O(N^2) four times as long.
Re:O(N^2) in CreateProcess by rightbyte on Monday April 22, 2019 @05:12PM (#19723050)
No, that's only true at the limit as n goes towards infinity.

And even if you see it as a approximation of growth for big n:s, you need to know "twice what" and "four times what" and "what's a big n" to have any use from it.

For the example with multiplication of 2 n-digit numbers:

https://en.wikipedia.org/wiki/Karatsuba_algorithm It's O(n^1.585). Need about 1000 digits before it's actually faster than "School book" O(n^2) multiplication.

https://en.wikipedia.org/wiki/Sch%C3%B6nhage%E2%80%93Strasse... It's O(n log n log log n). In practice faster than Karatsuba at 10,000 to 40,000 decimal digits.

Then there is the newest and hottest O(n log n) version, that's not practical at all.

Re:O(N^2) in CreateProcess by brucedawson on Monday April 22, 2019 @08:45PM (#19724597)
Sure, there are some cases where O() can be misleading, but those are the exceptions. You can work in software for a long time without being affected significantly by them, whereas using O(n^2) when you could use O(n) can make your code 1,000 times slower than usable, and it does this frequently.

I have fixed hundreds of O(n^2) algorithms over the years, made them O(n) or O(n log(n)), and made the product dramatically better. The fact that an O(n) algorithm can sometimes be slower than an O(n^2) feels more like pedantry than useful information in this context.

Re:O(N^2) in CreateProcess by magicalhippo on Monday April 22, 2019 @11:25AM (#19719605)
The point is that for most cases I'm dealing with things that are not extremely performance sensitive (ie every ms doesn't count), but which should handle arbitrary user input without grinding to a halt.

If I need a combination, I can always check for small N and call a different implementation.