[plt-scheme] iterate over characters in string

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Tue Aug 13 11:31:53 EDT 2002

[If you get two copies Noel, it is because I forgot to change the to-field]
Welsh wrote:
>   For list-related administrative tasks:
>     http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>
>> At Tue, 13 Aug 2002 14:23:03 GMT, MJ Ray wrote:
>>> Chris Uzdavinis <chris at atdesk.com> wrote:
>>>>   * is there any kind of for-each function that
>> works on a string at
>>>>     the byte level?

> There is probably something in srfi 13 or 14.  I can
> never remember which number means which srfi.

It is srfi-13. It provides string-fold and string-for-each.
I have collected a few variations. The test string is
of length 1000000. The srfi-13 versions works at the
string at the byte level.

The fastest of the srfi-13 versions is:

  (define (calc-checksum-jas2 line)
    (define kons (lambda (c sum) (+ sum (char->integer c))))
    (modulo (string-fold kons 0 line) 256))

The fastest of them all is

  (define (calc-checksum-cu line)
    (modulo (apply + (map char->integer (string->list line))) 256))

Note that the set! is the slowest of them all. Mutation is slow.

I wrapped them in a modulo, so the optimizer got a fair chance.
Furthermore I collect garbage before each test in order to
get similar timings. The result was:

orig
cpu time: 3024 real time: 3024 gc time: 0
mjr
cpu time: 2123 real time: 2123 gc time: 0
cu
cpu time: 1422 real time: 1422 gc time: 0
jas
cpu time: 3485 real time: 3485 gc time: 0
jas2
cpu time: 2924 real time: 2924 gc time: 0
jas3
cpu time: 4928 real time: 4928 gc time: 0
jas4
cpu time: 4677 real time: 4677 gc time: 0

O! I almost forgot. srfi-13 can be downloaded at
http://sourceforge.net/project/showfiles.php?group_id=19879&release_id=96118
and the documentation can be browsed at
http://srfi.schemers.org/srfi-13/srfi-13.html

Jens Axel Søgaard

(module checksum mzscheme
  (provide test-all)

  (require (lib "string.ss" "srfi" "13"))

  (define (calc-checksum line)
    (let loop ([checksum 0]
               [chars (string->list line)])
      (cond [(null? chars) (modulo checksum 256)]
            [else (loop (+ checksum
                           (char->integer (car chars)))
                        (cdr chars))])))

  (define (calc-checksum-mjr line)
    (let ((ck 0))
      (map (lambda (c) (set! ck (+ ck (char->integer c))))
           (string->list line))
      (modulo ck 256)))

  (define (calc-checksum-cu line)
    (modulo (apply + (map char->integer (string->list line))) 256))

  (define (calc-checksum-jas line)
    (define kons (lambda (c sum) (modulo (+ sum (char->integer c)) 256)))
    (string-fold kons 0 line))

  (define (calc-checksum-jas2 line)
    (define kons (lambda (c sum) (+ sum (char->integer c))))
    (modulo (string-fold kons 0 line) 256))

  (define (calc-checksum-jas3 line)
    (define sum 0)
    (define (update! c)
      (set! sum (modulo (+ sum (char->integer c)) 256)))
    (string-for-each update! line)
    sum)

  (define (calc-checksum-jas4 line)
    (define sum 0)
    (define (update! c)
      (set! sum (+ sum (char->integer c))))
    (string-for-each update! line)
    (modulo sum 256))

  (define (test sym cs)
    (display sym)
    (newline)
    (collect-garbage)
    (time (cs (make-string 1000000 #\a))))

  (define (test-all)
    (test 'orig calc-checksum)
    (test 'mjr  calc-checksum-mjr)
    (test 'cu   calc-checksum-cu)
    (test 'jas  calc-checksum-jas)
    (test 'jas2 calc-checksum-jas2)
    (test 'jas3 calc-checksum-jas3)
    (test 'jas4 calc-checksum-jas4)))

(require checksum)
(test-all)








Posted on the users mailing list.