Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] Re: Guru's please help improve ROT13 algorithm !

From: apwing:zonnet:nl at: 15-Dec-2003 15:13

Hi guys, thanks a lot for all the comments and the debate that followed. I think that things have been put into a better perspective now :-) Met vriendelijke groet / with kind regards, Arie van Wingerden http://home.zonnet.nl/rebolution ----- Original Message ----- From: Joel Neely To: [rebol-list--rebol--com] Sent: Sunday, December 14, 2003 10:24 PM Subject: [REBOL] Re: Guru's please help improve ROT13 algorithm ! I submitted a cleaner one (than what's on the ROT13 page) along with some remarks, and copied the list here, and then saw Sunanda's reply: [SunandaDH--aol--com] wrote:
> http://www.rebol.org/cgi-bin/cgiwrap/rebol/view-script.r?script=rot-13.r >
WRT that version, I'll add my $0.02... rot-13: func [ {Converts a string to or from Rot-13} data [any-string!] /local scrambled rot-chars rot-char ][ rot-chars: {anabobcpcdqderefsfgtghuhivijwjkxklylmzmANABOBCPCDQDEREFSFGTGHUHIVIJWJKXKLYLMZM} scrambled: copy "" foreach char data [ if none? (rot-char: select/case rot-chars char) [rot-char: char] insert tail scrambled :rot-char ] return scrambled ] My suggestions follow: 1) I prefer to avoid typo-prone strings when I can. 2) Both the above and my submission to the ROT13 site would benefit from comments explaining the construction of the translation string as related to SELECT/CASE. It is a nice REBOL-ism that we only need 39 characters per case as opposed to 52! 3) I'd rather initialize the result as an empty string with the full (known) length preallocated to avoid excessive memory management overhead for longer arguments. 4) The use of the get-word (:ROT-CHAR) is surprising (but marginally defensible by speed?) 5) The if-none-then-use-default pattern is a great opportunity to use another REBOL-ism, ANY. I did a little benchmarking with four versions: " code" - is the version from my earlier post, "if/get" - replaces the FOREACH body with if none? cc: select/case xlate ch [cc: ch] insert tail result :cc similar to the version in the script library " if" - simply replaces the get-word (:CC) with the word itself if none? cc: select/case xlate ch [cc: ch] insert tail result cc "either" - evaluates the replacement character as an expression as the last argument of the INSERT insert tail result either none? cc: select/case xlate ch [ch] [cc] The results of a quick timing test (50,000 evaluations of each function on a 243-character string) are
>> rot13/time-it 50000 datum
code: 108.356 if/get: 132.24 if: 133.502 either: 137.117 The use of the get-word saves about 1% to the run-time of the function (if/get vs is). The time for EITHER vs IF was a bit of a surprise to me, because it added another 3-4% to the run time. Comparing the object/method version vs a stand-alone function, we can pull a REBOL-persistence-of-series trick: rot13: func [s [string!] /local result xlate] [ if empty? xlate: "" [ for ch #"a" #"m" 1 [append xlate reduce [ch ch + 13 ch]] for ch #"A" #"M" 1 [append xlate reduce [ch ch + 13 ch]] ] result: make string! length? s foreach ch s [ insert tail result any [select/case xlate ch ch] ] result ] (not that I'd ever write somehing like that, for several reasons ;-) or embed the translation strings in place of the local XLATE, and get the following timings:
>> fn-vs-obj 50000 datum
method: 108.255 stateful: 107.405 stateless: 107.514 where "stateful" is the above ROT13 function, and "stateless" uses the literal instead of persistence. Any critiques or suggestions for improvement to my object-based version are welcome! -jn-