• Re: May the numbers speak - supplement

    From minforth@21:1/5 to All on Wed Jun 11 16:29:44 2025
    From the other optimizers team :o)
    Extra simple and easy to maintain
    (for well-formed hh:mm:ss):

    # : hms ':' parse evaluate ':' parse evaluate bl parse evaluate ; ok
    # hms 12:59:21 ok
    12 59 21 #

    --

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Rubin@21:1/5 to All on Thu Jun 12 02:59:56 2025
    This version with the string in memory, no error checking, and using a variable, seems simplest to me.

    variable p
    : advance ( -- ) 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit 10 * digit + ;
    : hms ( a u -- h m s ) drop p !
    2digit advance 2digit advance 2digit advance ;
    : test clearstack s" 12:34:56" hms ;

    test .s

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From mhx@21:1/5 to Paul Rubin on Thu Jun 12 11:04:46 2025
    On Thu, 12 Jun 2025 9:59:56 +0000, Paul Rubin wrote:

    This version with the string in memory, no error checking, and using a variable, seems simplest to me.

    variable p
    : advance ( -- ) 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit 10 * digit + ;
    : hms ( a u -- h m s ) drop p !
    2digit advance 2digit advance 2digit advance ;

    It doesn't do the same thing. It isn't faster, which points out
    the '60 *' and 'M* D+' are not the limiting factors.

    : TEST ( -- )
    CR ." \ dtimescan : " S" 12:34:56" TICKS-RESET dtimescan
    TICKS? UD. ." clock ticks elapsed, " UD.
    CR ." \ timestrscan : " S" 12:34:56" TICKS-RESET timestrscan
    TICKS? UD. ." clock ticks elapsed, " UD.
    CR ." \ HMS : " S" 12:34:56" TICKS-RESET hms
    TICKS? UD. ." clock ticks elapsed, " ROT . SWAP . . ;

    FORTH> TEST TEST TEST TEST
    \ dtimescan : 1257 clock ticks elapsed, 45296
    \ timestrscan : 419 clock ticks elapsed, 45296
    \ HMS : 419 clock ticks elapsed, 12 34 56
    \ dtimescan : 419 clock ticks elapsed, 45296
    \ timestrscan : 420 clock ticks elapsed, 45296
    \ HMS : 0 clock ticks elapsed, 12 34 56
    \ dtimescan : 419 clock ticks elapsed, 45296
    \ timestrscan : 419 clock ticks elapsed, 45296
    \ HMS : 419 clock ticks elapsed, 12 34 56
    \ dtimescan : 419 clock ticks elapsed, 45296
    \ timestrscan : 420 clock ticks elapsed, 45296
    \ HMS : 419 clock ticks elapsed, 12 34 56 ok

    FORTH> ' hms idis
    $01466000 : hms
    $0146600A pop rbx
    $0146600B pop rbx
    $0146600C mov $01463210 qword-offset, rbx
    $01466013 mov rbx, $01463210 qword-offset
    $0146601A movzx rbx, [rbx] byte
    $0146601D add $01463210 qword-offset, 1 b#
    $01466025 lea rbx, [rbx #-48 +] qword
    $01466029 lea rbx, [rbx rbx*4] qword
    $0146602D mov rdi, $01463210 qword-offset
    $01466034 movzx rdi, [rdi] byte
    $01466038 add $01463210 qword-offset, 1 b#
    $01466040 add $01463210 qword-offset, 1 b#
    $01466048 mov rax, $01463210 qword-offset
    $0146604F movzx rax, [rax] byte
    $01466052 add $01463210 qword-offset, 1 b#
    $0146605A lea rax, [rax #-48 +] qword
    $0146605E lea rax, [rax rax*4] qword
    $01466062 mov rdx, $01463210 qword-offset
    $01466069 movzx rdx, [rdx] byte
    $0146606C add $01463210 qword-offset, 1 b#
    $01466074 add $01463210 qword-offset, 1 b#
    $0146607C mov r9, $01463210 qword-offset
    $01466083 movzx r9, [r9 ] byte
    $01466087 add $01463210 qword-offset, 1 b#
    $0146608F lea r9, [r9 #-48 +] qword
    $01466093 lea r9, [r9 r9*4 ] qword
    $01466097 mov r10, $01463210 qword-offset
    $0146609E movzx r10, [r10] byte
    $014660A2 add $01463210 qword-offset, 1 b#
    $014660AA add $01463210 qword-offset, 1 b#
    $014660B2 lea rbx, [rdi rbx*2 #-48 +] qword
    $014660B7 push rbx
    $014660B8 lea rbx, [rdx rax*2 #-48 +] qword
    $014660BD push rbx
    $014660BE lea rbx, [r10 r9*2 #-48 +] qword
    $014660C3 push rbx
    $014660C4 ;

    -marcel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From ahmed@21:1/5 to Paul Rubin on Thu Jun 12 14:04:38 2025
    On Thu, 12 Jun 2025 9:59:56 +0000, Paul Rubin wrote:

    This version with the string in memory, no error checking, and using a variable, seems simplest to me.

    variable p
    : advance ( -- ) 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit 10 * digit + ;
    : hms ( a u -- h m s ) drop p !
    2digit advance 2digit advance 2digit advance ;
    : test clearstack s" 12:34:56" hms ;

    test .s

    Hi,
    Thanks for all the ideas.
    What about this? is it clear, readable, ...?

    I think it is the same as yours but use directly the return stack and
    advance manually with subtracting 528 whihc is 48*10+48 where 48 is '0'.

    : hms ( u n -- h m s)
    drop >r
    r@ c@ 10 * r@ 1+ c@ + 528 -
    r@ 3 + c@ 10 * r@ 4 + c@ + 528 -
    r@ 6 + c@ 10 * r@ 7 + c@ + 528 -
    rdrop ;

    s" 12:34:56" hms .s <3> 12 34 56 ok

    Ahmed

    --

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From minforth@21:1/5 to Paul Rubin on Thu Jun 12 15:01:58 2025
    On Thu, 12 Jun 2025 9:59:56 +0000, Paul Rubin wrote:

    This version with the string in memory, no error checking, and using a variable, seems simplest to me.

    variable p
    : advance ( -- ) 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit 10 * digit + ;
    : hms ( a u -- h m s ) drop p !
    2digit advance 2digit advance 2digit advance ;
    : test clearstack s" 12:34:56" hms ;

    test .s

    Yes, good point. In my toolbox are two words
    STR-PARSE ( a u c -- ap up )
    STR-PARSE-NAME ( a u -- ap up )
    as twins to the standard words. They also use SKIP / SCAN
    but work on strings in memory, without needing to switch
    SOURCE. Now and then they are quite handy.

    --

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From B. Pym@21:1/5 to Paul Rubin on Thu Jun 12 16:13:30 2025
    Paul Rubin wrote:

    : hms ( a u -- h m s ) drop p !
    2digit advance 2digit advance 2digit advance ;
    ^^^^^^^

    This serves no purpose.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Rubin@21:1/5 to B. Pym on Thu Jun 12 10:17:37 2025
    "B. Pym" <Nobody447095@here-nor-there.org> writes:
    : hms ( a u -- h m s ) drop p !
    2digit advance 2digit advance 2digit advance ;
    This serves no purpose.

    Yes I spotted that after posting. It could be worse. In C that might
    have been UB.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From peter@21:1/5 to Paul Rubin on Thu Jun 12 22:24:33 2025
    On Thu, 12 Jun 2025 02:59:56 -0700
    Paul Rubin <no.email@nospam.invalid> wrote:

    This version with the string in memory, no error checking, and using a variable, seems simplest to me.

    variable p
    : advance ( -- ) 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit 10 * digit + ;
    : hms ( a u -- h m s ) drop p !
    2digit advance 2digit advance 2digit advance ;
    : test clearstack s" 12:34:56" hms ;

    test .s

    This inspired me to write the following
    Requiring a well formed time string and a 64 bit cell size

    : hms ( a u -- h m s )
    drop @ $30303A30303A3030 -
    dup $FF0000FF0000FF00 and 8 rshift
    swap $00FF0000FF0000FF and dup 3 lshift swap 2* +
    +
    dup $ff and
    swap dup 24 rshift $ff and
    swap 48 rshift $ff and ;

    : test1 100000000 0 do "12:34:56" hms 2drop drop loop ;

    timer-reset test1 .elapsed 107 ms elapsed ok

    if I inline hmns the time goes down to 71 ms

    lxf64 now produces native code and works well!

    seea hms
    0x41FA70 488B5D00 mov rbx, qword [rbp]
    0x41FA74 488B1B mov rbx, qword [rbx]
    0x41FA77 48B830303A30303A3030 mov rax, 0x30303A30303A3030 0x41FA81 4829C3 sub rbx, rax
    0x41FA84 48B800FF0000FF0000FF mov rax, 0xFF0000FF0000FF00 0x41FA8E 4889D9 mov rcx, rbx
    0x41FA91 4821C1 and rcx, rax
    0x41FA94 48C1E908 shr rcx, 0x8
    0x41FA98 48B8FF0000FF0000FF00 mov rax, 0xFF0000FF0000FF
    0x41FAA2 4821C3 and rbx, rax
    0x41FAA5 4889D8 mov rax, rbx
    0x41FAA8 48C1E003 shl rax, 0x3
    0x41FAAC 48D1E3 shl rbx, 0x1
    0x41FAAF 4801C3 add rbx, rax
    0x41FAB2 4801CB add rbx, rcx
    0x41FAB5 4889D8 mov rax, rbx
    0x41FAB8 4825FF000000 and rax, 0xFF
    0x41FABE 4889D9 mov rcx, rbx
    0x41FAC1 48C1E918 shr rcx, 0x18
    0x41FAC5 4881E1FF000000 and rcx, 0xFF
    0x41FACC 48C1EB30 shr rbx, 0x30
    0x41FAD0 4881E3FF000000 and rbx, 0xFF
    0x41FAD7 48894DF8 mov qword [rbp-0x8], rcx
    0x41FADB 48894500 mov qword [rbp], rax
    0x41FADF 488D6DF8 lea rbp, [rbp-0x8]
    0x41FAE3 C3 ret
    116 bytes, 26 instructions

    Best Regards
    Peter Fälth

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Rubin@21:1/5 to mhx on Thu Jun 12 13:42:27 2025
    mhx@iae.nl (mhx) writes:
    It doesn't do the same thing. It isn't faster, which points out
    the '60 *' and 'M* D+' are not the limiting factors.

    Oh I copied the interface from another post, didn't realize it was
    supposed to convert to seconds. I didn't care about the speed since any slowness in any of these versions can be blamed on the compiler ;).
    Here is another version:

    variable p
    : advance 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit 10 * digit + advance ; \ skips trailing colon
    : hms ( a u -- n ) drop p ! 2digit 60 * 2digit + 60 * 2digit + ;
    : test clearstack s" 12:34:56" hms ;

    test .s

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From mhx@21:1/5 to Paul Rubin on Thu Jun 12 21:22:01 2025
    On Thu, 12 Jun 2025 20:42:27 +0000, Paul Rubin wrote:

    mhx@iae.nl (mhx) writes:
    It doesn't do the same thing. It isn't faster, which points out
    the '60 *' and 'M* D+' are not the limiting factors.

    Oh I copied the interface from another post, didn't realize it was
    supposed to convert to seconds. I didn't care about the speed since any slowness in any of these versions can be blamed on the compiler ;).
    Here is another version:

    variable p
    : advance 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit 10 * digit + advance ; \ skips trailing colon
    : hms ( a u -- n ) drop p ! 2digit 60 * 2digit + 60 * 2digit + ;
    : test clearstack s" 12:34:56" hms ;

    test .s

    iSPICE> TEST TEST TEST TEST
    \ dtimescan : 2515 clock ticks elapsed, 45296
    \ timestrscan : 419 clock ticks elapsed, 45296
    \ HMS : 419 clock ticks elapsed, 45296
    \ dtimescan : 419 clock ticks elapsed, 45296
    \ timestrscan : 420 clock ticks elapsed, 45296
    \ HMS : 420 clock ticks elapsed, 45296
    \ dtimescan : 838 clock ticks elapsed, 45296
    \ timestrscan : 419 clock ticks elapsed, 45296
    \ HMS : 419 clock ticks elapsed, 45296
    \ dtimescan : 419 clock ticks elapsed, 45296
    \ timestrscan : 419 clock ticks elapsed, 45296
    \ HMS : 419 clock ticks elapsed, 45296 ok

    It makes no difference. Whatever is holding it down must
    be quite severe.

    -marcel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Rubin@21:1/5 to mhx on Thu Jun 12 15:01:07 2025
    mhx@iae.nl (mhx) writes:
    iSPICE> TEST TEST TEST TEST
    \ dtimescan : 2515 clock ticks elapsed, 45296
    \ timestrscan : 419 clock ticks elapsed, 45296
    \ HMS : 419 clock ticks elapsed, 45296
    It makes no difference. Whatever is holding it down must
    be quite severe.

    Is dtimescan the one that uses double word arithmetic for 16 bit
    processors? It's doing more stuff, I would think. Weird that it
    catches up after a few tries. Cache warming?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From B. Pym@21:1/5 to Paul Rubin on Thu Jun 12 22:24:44 2025
    Paul Rubin wrote:

    This version with the string in memory, no error checking, and using a variable, seems simplest to me.

    variable p
    : advance ( -- ) 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit 10 * digit + ;
    : hms ( a u -- h m s ) drop p !
    2digit advance 2digit advance 2digit advance ;
    : test clearstack s" 12:34:56" hms ;

    test .s

    : keep { lo hi adr len } lo adr len ;
    : get { adr len } 0. adr len >number keep 1 /string ;
    : hms ( adr len -- h m s) get get get 2drop ;
    : test clearstack s" 12:34:56" hms ;

    test .s

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From mhx@21:1/5 to Paul Rubin on Fri Jun 13 08:43:44 2025
    On Thu, 12 Jun 2025 22:01:07 +0000, Paul Rubin wrote:

    mhx@iae.nl (mhx) writes:
    iSPICE> TEST TEST TEST TEST
    \ dtimescan : 2515 clock ticks elapsed, 45296
    \ timestrscan : 419 clock ticks elapsed, 45296
    \ HMS : 419 clock ticks elapsed, 45296
    It makes no difference. Whatever is holding it down must
    be quite severe.

    Is dtimescan the one that uses double word arithmetic for 16 bit
    processors? It's doing more stuff, I would think. Weird that it
    catches up after a few tries. Cache warming?

    The TICKS? word apparently can't be trusted under Windows 11. This
    is better:

    #2000000 VALUE #iters
    CREATE num ," 12:34:56"
    : .SECS MS? #1000000 #iters 3 * */ ." / " . ." ns per iteration." ;

    : TEST2 ( -- )
    CR
    CR ." \ dtimescan : " TIMER-RESET num C@+
    #iters 0 ?DO 2DUP dtimescan 2DROP
    2DUP dtimescan 2DROP
    2DUP dtimescan 2DROP LOOP dtimescan UD.
    SECS
    CR ." \ timestrscan : " TIMER-RESET num C@+
    #iters 0 ?DO 2DUP timestrscan 2DROP
    2DUP timestrscan 2DROP
    2DUP timestrscan 2DROP LOOP timestrscan UD.
    SECS
    CR ." \ HMS : " TIMER-RESET num C@+
    #iters 0 ?DO 2DUP hms DROP
    2DUP hms DROP
    2DUP hms DROP LOOP hms .
    SECS
    CR ." \ HMS2 : " TIMER-RESET num C@+
    #iters 0 ?DO 2DUP hms2 3DROP
    2DUP hms2 3DROP
    2DUP hms2 3DROP LOOP hms2 ROT . SWAP . .
    SECS ;

    CLS TEST2 TEST2 TEST2 TEST2

    \ dtimescan : 45296 / 15 ns per iteration.
    \ timestrscan : 45296 / 13 ns per iteration.
    \ HMS : 45296 / 5 ns per iteration.
    \ HMS2 : 12 34 56 / 53 ns per iteration.

    \ dtimescan : 45296 / 15 ns per iteration.
    \ timestrscan : 45296 / 14 ns per iteration.
    \ HMS : 45296 / 5 ns per iteration.
    \ HMS2 : 12 34 56 / 53 ns per iteration.

    \ dtimescan : 45296 / 16 ns per iteration.
    \ timestrscan : 45296 / 14 ns per iteration.
    \ HMS : 45296 / 5 ns per iteration.
    \ HMS2 : 12 34 56 / 53 ns per iteration.

    \ dtimescan : 45296 / 15 ns per iteration.
    \ timestrscan : 45296 / 14 ns per iteration.
    \ HMS : 45296 / 5 ns per iteration.
    \ HMS2 : 12 34 56 / 53 ns per iteration. ok

    HMS is three times faster than dtimescan and timestrscan, while
    HMS2 is 3.5 times slower (as expected).

    In practice, I'd use some variant of hms2.

    -marcel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From albert@spenarnc.xs4all.nl@21:1/5 to B. Pym on Fri Jun 13 15:16:35 2025
    In article <102fk3b$2ut8q$1@dont-email.me>,
    B. Pym <Nobody447095@here-nor-there.org> wrote:
    Paul Rubin wrote:

    This version with the string in memory, no error checking, and using a
    variable, seems simplest to me.

    variable p
    : advance ( -- ) 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit 10 * digit + ;
    : hms ( a u -- h m s ) drop p !
    2digit advance 2digit advance 2digit advance ;
    : test clearstack s" 12:34:56" hms ;

    test .s

    : keep { lo hi adr len } lo adr len ;
    : get { adr len } 0. adr len >number keep 1 /string ;
    : hms ( adr len -- h m s) get get get 2drop ;
    : test clearstack s" 12:34:56" hms ;


    Once more the superiority of the $@ $! $/ $\ wordset is shown,
    also shunning the clunky [CHAR]/CHAR stuff.
    Low level abstractions wins the day.

    : SDSWAP ROT ROT ;

    : hms &: $/ EVALUATE SDSWAP &: $/ EVALUATE SDSWAP EVALUATE ;

    "12:34:56" hms
    .S
    12 34 56 OK

    Most errors meet with an ERROR 10, malformed number.
    Not that I know what `hms is supposed to do,
    especially with regards to response to errors.


    test .s

    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Rubin@21:1/5 to Hans Bezemer on Fri Jun 13 10:44:42 2025
    Hans Bezemer <the.beez.speaks@gmail.com> writes:
    That's why I consider the use of global variables in library functions
    worse than locals. You're polluting the namespace.

    Obviously there are ways around that with wordlists, but it would be
    nice if doing that was more convenient. You could have program sections
    with their own encapsulated variables.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Rubin@21:1/5 to mhx on Fri Jun 13 10:47:24 2025
    mhx@iae.nl (mhx) writes:
    HMS is three times faster than dtimescan and timestrscan, while
    HMS2 is 3.5 times slower (as expected).

    Is HMS the one that I posted, and HMS2 the version that's almost the
    same? Why the speed difference: just because of the extra memory
    traffic of leaving extra things on the stack?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From mhx@21:1/5 to Paul Rubin on Fri Jun 13 20:22:32 2025
    On Fri, 13 Jun 2025 17:47:24 +0000, Paul Rubin wrote:

    mhx@iae.nl (mhx) writes:
    HMS is three times faster than dtimescan and timestrscan, while
    HMS2 is 3.5 times slower (as expected).

    Is HMS the one that I posted, and HMS2 the version that's almost the
    same? Why the speed difference: just because of the extra memory
    traffic of leaving extra things on the stack?

    HSM see below.

    HSM2 is from dxf and uses >NUMBER . That is the kitchen sink compared
    to '60 * ...' so of course it is much slower with the current
    optimization level of iForth.

    -marcel

    --
    ----------------------------------------------------------------------
    ANEW -timescan

    : dtimescan ( addr count -- d )
    over swap + >r >r
    0. r> 0
    begin
    over r@ <
    while
    over c@ ':'
    = if swap >r s>d d+ #60 1 m*/ r> 0
    else #10 * over c@ '0' - +
    endif
    swap 1+ swap
    repeat
    -r nip s>d d+ ;

    : timestrscan ( addr count -- d )
    1 1 LOCALS| c6 c1 |
    0. 2SWAP
    OVER + 1- ?DO
    I C@ DUP ':' =
    IF DROP
    c6 #60 * TO c6
    1 TO C1
    ELSE '0' - C1 * C6 M* D+
    #10 TO C1
    ENDIF
    -1 +LOOP ;

    variable p
    : advance 1 p +! ;
    : digit ( -- n ) p @ c@ '0' - advance ;
    : 2digit ( -- n ) digit #10 * digit + advance ; \ skips trailing colon
    : hms ( a u -- n ) drop p ! 2digit #60 * 2digit + #60 * 2digit + ;

    : (number) ( adr len -- ud adr' len' ) 0. 2swap >number ;
    : get ( adr len -- u adr' len' ) (number) rot drop 1 /string ;
    : hms2 ( adr len -- h m s) get get get 2drop ;

    : TEST ( -- )
    CR ." \ dtimescan : " S" 12:34:56" TICKS-RESET dtimescan
    TICKS? UD. ." clock ticks elapsed, " UD.
    CR ." \ timestrscan : " S" 12:34:56" TICKS-RESET timestrscan
    TICKS? UD. ." clock ticks elapsed, " UD.
    CR ." \ HMS : " S" 12:34:56" TICKS-RESET hms
    TICKS? UD. ." clock ticks elapsed, " .
    CR ." \ HMS2 : " S" 12:34:56" TICKS-RESET hms2
    TICKS? UD. ." clock ticks elapsed, " ROT . SWAP . . ;

    TEST

    #2000000 VALUE #iters
    CREATE num ," 12:34:56"
    : .SECS MS? #1000000 #iters 3 * */ ." / " . ." ns per iteration." ;

    : TEST2 ( -- )
    CR
    CR ." \ dtimescan : " TIMER-RESET num C@+ #iters 0 ?DO 2DUP
    dtimescan 2DROP 2DUP dtimescan 2DROP 2DUP dtimescan 2DROP
    LOOP
    dtimescan UD. .SECS
    CR ." \ timestrscan : " TIMER-RESET num C@+ #iters 0 ?DO 2DUP
    timestrscan 2DROP 2DUP timestrscan 2DROP 2DUP timestrscan 2DROP
    LOOP
    timestrscan UD. .SECS
    CR ." \ HMS : " TIMER-RESET num C@+ #iters 0 ?DO 2DUP
    hms DROP 2DUP hms DROP 2DUP hms DROP
    LOOP
    hms . .SECS
    CR ." \ HMS2 : " TIMER-RESET num C@+ #iters 0 ?DO 2DUP
    hms2 3DROP 2DUP hms2 3DROP 2DUP hms2 3DROP
    LOOP
    hms2 ROT . SWAP . . .SECS ;

    TEST2

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)