User talk:WillNess: Difference between revisions

From Rosetta Code
Content added Content deleted
(reply to your comment in my talk page...)
Line 35: Line 35:


: Thanks!! -- [[User:WillNess|WillNess]] ([[User talk:WillNess|talk]]) 14:47, 17 January 2016 (UTC)
: Thanks!! -- [[User:WillNess|WillNess]] ([[User talk:WillNess|talk]]) 14:47, 17 January 2016 (UTC)

== Space complexity improvement -- [[Hamming numbers]] ==

Hi, glad you enjoyed my tweak.

I believe the way you apply it works out the same at the end as the way I do. I add the empirical error correction factor (which quickly becomes about a constant factor of the log of output number for even reasonable ranges) times the original estimate of the log value directly to the desired 'n' number as in the nth Hamming number to calculate a new estimated value as the upper bound of the band. The lower bound is then just the same difference lower (or twice the difference lower than the upper bound). Using my method, I don't have to produce fractions for both the upper bound and the difference.

As to the space complexity, since the log estimate is basically n^(1/3), and the error band is proportional to the log, then the space complexity is as calculated and quite quickly approaches this limit.

Of course the space complexity makes very little difference in speed just as the sorting algorithm chosen makes very little difference as operations are limited to the size of the error band which is negligible as compared to the amount of time spent in the inner loops; for very large ranges there is a slight slowdown from ideal time complexity as the size of the error band gets larger than the various CPU caches.

Yes, you are right that 32-bit Haskell is quite slow at handling Word64's, which in my version is why I limit the inner loop i, j, and k values to Word32 (which under the covers Integers are calculated as when the ranges are small enough). The GHC Native Code Generator (NCG) has a known [https://ghc.haskell.org/trac/ghc/ticket/8971 problem, still there in version 8.0.1], especially for 32-bit code, in efficiently allocating registers that is known to be at least twice as slow as 64-bit code for many algorithms, so it is actually amazing that you managed to make this run as fast as you did on IdeOne.

The main time expended is due to the inner loops, and even in 64-bit code GHC is still slower by a constant factor than many other languages, even lowly C#/F#, likely due to the time spent building the (lazy) error list instead of using arrays. I think that one could write code that would be as fast as the others, but one would have to define an instance of an STUArray to hold the unboxed tuples used (perhaps as their own packed type class instead of tuples) and the code would get messy for submission to RosettaCode. For [http://rosettacode.org/wiki/Hamming_numbers#Extremely_fast_non-enumerating_version_sorting_values_in_error_band my F# version] I use non-lazy lists (at a constant factor cost in memory use for the tail links) very effectively, running almost as fast as a version using mutable arrays such as C#. The fastest versions in various languages fun about twice as fast as the Haskell version (64-bit code).

Yes, we have had the discussion about type signatures before re: Sieve of Eratosthenes; there is a reason they are recommended in the Haskell style guides for outer definitions.

You know me from previous discussions on this and other forums: I like maximum efficiency from any given algorithm including this one, and I think that with this tweak we are pretty well there. --[[User:GordonBGood|GordonBGood]] ([[User talk:GordonBGood|talk]]) 02:13, 19 August 2016 (UTC)

Revision as of 02:17, 19 August 2016

Hi WillNess, If reporting runtimes please restrict it to comparative times between two implementations using the same language and try and use loose comparative terms such as 'around twice' rather than actual times as anything other than that is very difficult to interpret w.r.t. run conditions, OS, ... And RC doesn't set out to be a site for comparative run-time evaluations.
Thanks, --Paddy3118 11:37, 5 September 2011 (UTC)

Hi, you made an edit to Hamming numbers with the comment "according to docs for tee() storage is NOT shared among its iterators". I would like to know what you mean. What does it mean that storage is not shared. --208.80.119.67 00:49, 9 September 2011 (UTC)

Documentation says it is "equivalent to":

<lang Python>def tee(iterable, n=2):

   it = iter(iterable)
   deques = [collections.deque() for i in range(n)]
   def gen(mydeque):
       while True:
           if not mydeque:             # when the local deque is empty
               newval = next(it)       # fetch a new value and
               for d in deques:        # load it to all the deques
                   d.append(newval)
           yield mydeque.popleft()
   return tuple(gen(d) for d in deques)

</lang>

I read it to show that each generator produced by tee() holds on to its own dequeue (list with pop() and append()). When a new item is taken from the original iterable, it is appended separately into each one of the dequeues. Were they all to share one dequeue amongst themselves, that would be a shared storage. popleft() wouldn't be always called, but only when the leftmost of internal iterators pointing into internal list would get advanced. WillNess 10:53, 9 September 2011 (UTC)

Good morning, Can you please undo the double-space style changes that you made on the Sieve thread-based solution? I find that kind of spacing much harder to read. Also, my intention in writing that code was to demonstrate Racket's ability to express solutions in different paradigms as well as show how such different solutions are really doing the same thing. For this reason I would like to keep unnecessary optimizations at a very minimal level. It's therefore questionable that the changes that you made (stepping by 2x, explicit 3 in the beginning) are worth it. Whatever speedup you get as a result of changing the argument order is definitely not worth it for this goal. So please avoid such optimizations -- not turning this website into a festival of obscure optimizations like the language shootout thing is one of its most appealing properties. Thanks, --Elibarzilay (talk) 03:58, 6 November 2015 (UTC)

Hi, Eli. About the spacing. For me, it is much more readable that way, and since I'm much less proficient than you are (no emotional charge here, just plain fact) at reading and writing Scheme/Racket, I can only assume that it will also be much easier for a casual reader, unfamiliar with the language -- which I assume is the target audience of this site. As for the evens "optimization", I'll try to revert it. -- WillNess (talk) 13:00, 6 November 2015 (UTC)
I remember now how that happened. You had (ints-from 3 2) there, and I just went along with your 2, instead of correcting it to 1. WillNess (talk) 13:39, 6 November 2015 (UTC)
I don't think that that code is mine, at least not directly (the whole sieve thing went out of control with all kinds of arguments around it, which lead to a pile of stuff that goes against simple examples, and I got tired of fighting it at some point). Still, I'd like to see it stays at roughly the same level with no further obscuring optimizations... As for the spacing, being a newbie or not is really not a good factor (if only because many real newbies writing single parens on a line in an attempt to mimic C), instead, it should be as standard looking as possible, and double spaces is something that is not. --Elibarzilay (talk) 19:38, 9 November 2015 (UTC)
here's your edit with the (ints-from 3 2) throughout, and some additional spacing in the else clauses which I interpreted as arbitrary space to achieve code alignment for visual effect. I'll remove the double spacing an retain that additional space in the else clauses, shortly. -- WillNess (talk) 20:54, 9 November 2015 (UTC)
The edits being done by me don't say much, since code was shuffled a lot, and it's likely that I copied and/or translated things while doing that. But whether I copied it or I did it, the general thing is that optimizations that obscure the code should be avoided here... Thanks for the edits! --Elibarzilay (talk) 22:45, 10 November 2015 (UTC)
I'm not seeking to assign any blame obviously, I just didn't know (then) how to interpret your intent and took it to the other side, I guess. But what you're saying makes perfect sense. Thanks, -- WillNess (talk) 19:37, 11 November 2015 (UTC)
No problems -- I just wanted to clarify how things got to where they are, and even though I did many edits the result is not something I'm too happy with... The original --simple-- code that I had in a way that nicely demonstrates the similarities between laziness, threads, and generators is now stashed in the obscurely named "Sequence of primes by Trial Division" -- the sieve code is the results of many butcherings of that code, once there were complaints that the simple version is not really an "Eratosthenes Sieve" (I'm still not convinced, the rules sound like something that was retrofitted to the greek guy). --Elibarzilay (talk) 01:02, 18 November 2015 (UTC)
About the difference, maybe you'll find these old lazy-Lisp definitions with rem (pg 3), 1976 and with (+) (pg 2), 1987 interesting. -- WillNess (talk) 11:56, 19 November 2015 (UTC)

IP block fixed.

The reason you saw the IP block was because MediaWiki inadvertently blocked the IP address of the Cloudflare backend you were connecting in through. --Michael Mol (talk) 19:12, 3 January 2016 (UTC)

Thanks!! -- WillNess (talk) 14:47, 17 January 2016 (UTC)

Space complexity improvement -- Hamming numbers

Hi, glad you enjoyed my tweak.

I believe the way you apply it works out the same at the end as the way I do. I add the empirical error correction factor (which quickly becomes about a constant factor of the log of output number for even reasonable ranges) times the original estimate of the log value directly to the desired 'n' number as in the nth Hamming number to calculate a new estimated value as the upper bound of the band. The lower bound is then just the same difference lower (or twice the difference lower than the upper bound). Using my method, I don't have to produce fractions for both the upper bound and the difference.

As to the space complexity, since the log estimate is basically n^(1/3), and the error band is proportional to the log, then the space complexity is as calculated and quite quickly approaches this limit.

Of course the space complexity makes very little difference in speed just as the sorting algorithm chosen makes very little difference as operations are limited to the size of the error band which is negligible as compared to the amount of time spent in the inner loops; for very large ranges there is a slight slowdown from ideal time complexity as the size of the error band gets larger than the various CPU caches.

Yes, you are right that 32-bit Haskell is quite slow at handling Word64's, which in my version is why I limit the inner loop i, j, and k values to Word32 (which under the covers Integers are calculated as when the ranges are small enough). The GHC Native Code Generator (NCG) has a known problem, still there in version 8.0.1, especially for 32-bit code, in efficiently allocating registers that is known to be at least twice as slow as 64-bit code for many algorithms, so it is actually amazing that you managed to make this run as fast as you did on IdeOne.

The main time expended is due to the inner loops, and even in 64-bit code GHC is still slower by a constant factor than many other languages, even lowly C#/F#, likely due to the time spent building the (lazy) error list instead of using arrays. I think that one could write code that would be as fast as the others, but one would have to define an instance of an STUArray to hold the unboxed tuples used (perhaps as their own packed type class instead of tuples) and the code would get messy for submission to RosettaCode. For my F# version I use non-lazy lists (at a constant factor cost in memory use for the tail links) very effectively, running almost as fast as a version using mutable arrays such as C#. The fastest versions in various languages fun about twice as fast as the Haskell version (64-bit code).

Yes, we have had the discussion about type signatures before re: Sieve of Eratosthenes; there is a reason they are recommended in the Haskell style guides for outer definitions.

You know me from previous discussions on this and other forums: I like maximum efficiency from any given algorithm including this one, and I think that with this tweak we are pretty well there. --GordonBGood (talk) 02:13, 19 August 2016 (UTC)