• DLSHIFT and DRSHIFT

    From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Tue Mar 26 17:01:53 2024
    From Newsgroup: comp.lang.forth

    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior
    thread.

    Tests needed.

    --
    Krishna Myneni


    === Start Code ===

    1 cells 3 lshift constant BITS_PER_CELL
    BITS_PER_CELL 2* constant BITS_PER_DOUBLE

    \ Return the u least significant bits of cell value u1
    \ as the most significant bits of u2
    : lsbits ( u1 u -- u2 )
    BITS_PER_CELL min
    BITS_PER_CELL - negate
    lshift ;

    \ Return the u most significant bits of cell value u1
    \ as the least significant bits of u2
    : msbits ( u1 u -- u2 )
    BITS_PER_CELL min
    BITS_PER_CELL - negate
    rshift ;

    0 value ubits

    \ u is the number of bits to shift

    : DLSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL > IF
    drop \ high double has been left shifted out
    ubits BITS_PER_CELL - lshift
    0 swap \ new low double
    ELSE
    ubits lshift swap
    dup >r
    ubits msbits or
    r> ubits lshift
    swap
    THEN ;

    : DRSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL > IF
    nip \ low double has been right shifted out
    ubits BITS_PER_CELL - rshift
    0 \ new high double
    ELSE
    swap ubits rshift
    swap dup >r
    ubits lsbits or
    r> ubits rshift
    THEN ;

    === End Code ===
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Tue Mar 26 19:57:49 2024
    From Newsgroup: comp.lang.forth

    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior thread.

    Tests needed.

    Just tested DLSHIFT and found weird things going on. Traced the problem
    to LSHIFT.


    kforth64

    1 64 LSHIFT . \ expected to get zero
    1 \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Gforth does the same thing

    1 64 LSHIFT . 1
    1 65 LSHIFT . 2
    etc.


    We shouldn't have an ambiguous condition here because of some
    idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    --
    Krishna





    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Tue Mar 26 22:14:04 2024
    From Newsgroup: comp.lang.forth

    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior thread.
    ...

    This version fixes the issue with the ambiguity of LSHIFT and RSHIFT,
    and gives the behavior of DLSHIFT and DRSHIFT which I want. Tests
    included below for 32-bit and 64-bit systems.

    --
    KM

    === dshift.4th ===
    \ dshift.4th
    \
    \ Source code definitions of DLSHIFT and DRSHIFT

    1 cells 3 lshift constant BITS_PER_CELL
    BITS_PER_CELL 2* constant BITS_PER_DOUBLE

    \ Return the u least significant bits of cell value u1
    \ as the most significant bits of u2
    : lsbits ( u1 u -- u2 )
    BITS_PER_CELL min
    BITS_PER_CELL - negate
    lshift ;

    \ Return the u most significant bits of cell value u1
    \ as the least significant bits of u2
    : msbits ( u1 u -- u2 )
    BITS_PER_CELL min
    BITS_PER_CELL - negate
    rshift ;

    0 value ubits

    \ u is the number of bits to shift

    : DLSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL >= IF
    drop \ high double has been left shifted out
    ubits BITS_PER_CELL -
    dup BITS_PER_CELL = IF
    2drop 0 0
    ELSE
    lshift 0 swap
    THEN
    ELSE
    ubits lshift swap
    dup >r
    ubits msbits or
    r> ubits lshift
    swap
    THEN ;

    : DRSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL >= IF
    nip \ low double has been right shifted out
    ubits BITS_PER_CELL -
    dup BITS_PER_CELL = IF
    2drop 0 0
    ELSE
    rshift 0
    THEN
    ELSE
    swap ubits rshift
    swap dup >r
    ubits lsbits or
    r> ubits rshift
    THEN ;

    === End of dshift.4th ===

    Test Code

    === dshift-test.4th ===
    \ dshift-test.4th
    \
    include ans-words \ <-- only for kForth
    include ttester
    include dshift

    HEX

    TESTING DLSHIFT DRSHIFT

    t{ 03 01 BITS_PER_CELL dlshift -> 00 03 }t
    t{ FF 00 BITS_PER_CELL dlshift -> 00 FF }t
    t{ 00 01 BITS_PER_CELL drshift -> 01 00 }t
    t{ 00 FF BITS_PER_CELL drshift -> FF 00 }t
    t{ -1 -1 BITS_PER_DOUBLE dlshift -> 00 00 }t
    t{ -1 -1 BITS_PER_DOUBLE drshift -> 00 00 }t

    BITS_PER_CELL 20 = [IF]
    t{ 03 01 BITS_PER_CELL 1- dlshift -> 80000000 80000001 }t
    t{ 80000000 02 1 dlshift -> 00 05 }t
    t{ 07 03 1 drshift -> 80000003 01 }t
    [THEN]

    BITS_PER_CELL 40 = [IF]
    t{ 03 01 BITS_PER_CELL 1- dlshift -> 8000000000000000 8000000000000001 }t
    t{ 8000000000000000 02 1 dlshift -> 00 05 }t
    t{ 07 03 1 drshift -> 8000000000000003 01 }t
    [THEN]

    DECIMAL

    === end of dshift-test.4th ===




    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Wed Mar 27 07:53:32 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    1 64 LSHIFT . \ expected to get zero
    1 \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Gforth does the same thing

    1 64 LSHIFT . 1
    1 65 LSHIFT . 2
    etc.


    We shouldn't have an ambiguous condition here because of some
    idiosyncratic behavior of the SHL instruction!

    On one hand, programmers expect the result of ( n m ) LSHIFT and ( n m
    ) RSHIFT to be 0 when m>=CELL_BITS. As you write:

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    OTOH, it's relatively rare to need this, so most computer architects
    have decided not to pay the relatively small hardware cost to produce
    this result, and instead only consider the lower 5 or 6 bits of the
    shift amount. The cost in language implementations is a little higher
    than at the hardware level, and various programming languages,
    including Forth have decided to leave this unspecified (there are also architectures where one bit more is used, and IIRC also hardware (IIRC
    Power) where a result of 0 is guaranteed).

    One interesting case is Java, which specifies the language pretty
    completely in order to make Java write-once-run-everywhere. Java's
    designers chose to go along with the common practice in computer
    architecture <https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.19>:

    |If the promoted type of the left-hand operand is int, then only the
    |five lowest-order bits of the right-hand operand are used as the shift |distance.

    |If the promoted type of the left-hand operand is long, then only the
    |six lowest-order bits of the right-hand operand are used as the shift |distance.

    See also
    <https://forth-standard.org/standard/core/LSHIFT#contribution-335>.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023: https://euro.theforth.net/2023
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Wed Mar 27 09:34:25 2024
    From Newsgroup: comp.lang.forth

    In article <utvgki$2ciso$1@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior >thread.

    Tests needed.

    --
    Krishna Myneni


    === Start Code ===

    1 cells 3 lshift constant BITS_PER_CELL
    BITS_PER_CELL 2* constant BITS_PER_DOUBLE

    \ Return the u least significant bits of cell value u1
    \ as the most significant bits of u2
    : lsbits ( u1 u -- u2 )
    BITS_PER_CELL min
    BITS_PER_CELL - negate
    lshift ;

    \ Return the u most significant bits of cell value u1
    \ as the least significant bits of u2
    : msbits ( u1 u -- u2 )
    BITS_PER_CELL min
    BITS_PER_CELL - negate
    rshift ;

    0 value ubits

    \ u is the number of bits to shift

    : DLSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL > IF
    drop \ high double has been left shifted out
    ubits BITS_PER_CELL - lshift
    0 swap \ new low double
    ELSE
    ubits lshift swap
    dup >r
    ubits msbits or
    r> ubits lshift
    swap
    THEN ;

    : DRSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_DOUBLE min dup to ubits
    BITS_PER_CELL > IF
    nip \ low double has been right shifted out
    ubits BITS_PER_CELL - rshift
    0 \ new high double
    ELSE
    swap ubits rshift
    swap dup >r
    ubits lsbits or
    r> ubits rshift
    THEN ;

    === End Code ===

    These words should be in assembler anyway.
    So a rigorous testset is more valuable than a supposedly
    standard implementation.

    Groetjes Albert
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat purring. - the Wise from Antrim -
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Ruvim@ruvim.pinka@gmail.com to comp.lang.forth on Wed Mar 27 15:26:29 2024
    From Newsgroup: comp.lang.forth

    On 2024-03-27 04:57, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior
    thread.

    Tests needed.

    Just tested DLSHIFT and found weird things going on. Traced the problem
    to LSHIFT.


    kforth64

    1 64 LSHIFT .  \ expected to get zero
    1              \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    [...]
    We shouldn't have an ambiguous condition here because of some
    idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a
    single shift of `x` by `u` bits should always be equivalent to `u`
    sequential shifts by 1 bit.

    But neither the standard nor implementations follow this idea.

    And I agree, this is rarely needed. So if a program requires this
    behavior, it can test the behavior of "shift" operations in this regard
    and redefine them in its own word list as:

    : lshift ( x u -- x )
    dup bits_per_cell u< if lshift exit then
    2drop 0
    ;


    [1] An ambiguous condition in LSHIFT (2024-02-05) <https://forth-standard.org/standard/core/LSHIFT#contribution-335>

    --
    Ruvim

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Wed Mar 27 07:28:05 2024
    From Newsgroup: comp.lang.forth

    On 3/27/24 06:26, Ruvim wrote:
    On 2024-03-27 04:57, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number
    left shift and right shift), over full shift range, per discussion in
    prior thread.

    Tests needed.

    Just tested DLSHIFT and found weird things going on. Traced the
    problem to LSHIFT.


    kforth64

    1 64 LSHIFT .  \ expected to get zero
    1              \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    [...]
    We shouldn't have an ambiguous condition here because of some
    idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a
    single shift of `x` by `u` bits should always be equivalent to `u` sequential shifts by 1 bit.


    I really think it is a bad idea to have UB in the spec of LSHIFT and
    RSHIFT due to the arbitrariness of low level shift operations at the
    hardware level. Here we have a chance to remove that UB and guarantee that

    1 BITS_PER_CELL LSHIFT returns zero
    and
    1 BITS_PER_CELL RSHIFT returns zero

    so that the expected result for a shift operation on the cell operand
    does not have UB.

    Efficiency because of extra instructions needed to implement this
    guarantee are not even worth bothering about -- we are not C.

    One would also expect the following two expressions to be consistent

    1 64 LSHIFT .

    and

    : TEST2* 1 64 0 DO 2* LOOP . ;
    TEST2*

    Currently, on some systems (kForth and Gforth), we get,

    1 64 LSHIFT . \ gives 1
    TEST2* \ gives 0

    For system implementers to ensure LSHIFT uses 6 bits of the shift count
    would be trivial and should not break past code provided that code did
    not use specific behavior which was called out as undefined behavior in
    the standard.

    If we get enough common practice in systems to have LSHIFT and RSHIFT
    behave in a consistent and expected manner, then it can be standardized.
    The important thing is to avoid nonsense in the language spec because of low-level hardware choices.

    --
    Krishna





    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Wed Mar 27 08:21:47 2024
    From Newsgroup: comp.lang.forth

    On 3/27/24 02:53, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    1 64 LSHIFT . \ expected to get zero
    1 \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    ...

    One interesting case is Java, which specifies the language pretty
    completely in order to make Java write-once-run-everywhere. Java's
    designers chose to go along with the common practice in computer
    architecture <https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.19>:

    |If the promoted type of the left-hand operand is int, then only the
    |five lowest-order bits of the right-hand operand are used as the shift |distance.

    |If the promoted type of the left-hand operand is long, then only the
    |six lowest-order bits of the right-hand operand are used as the shift |distance.


    For Forth, it would seem reasonable and natural to guarantee that the
    number of bits in the shift count which are honored are enough to
    represent the data stack width in bits. This would ensure that

    1 u LSHIFT

    and

    -1 u RSHIFT

    would be zero for u >= BITS_PER_CELL.

    --
    Krishna

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Wed Mar 27 08:24:56 2024
    From Newsgroup: comp.lang.forth

    On 3/27/24 03:34, albert@spenarnc.xs4all.nl wrote:
    In article <utvgki$2ciso$1@dont-email.me>,
    Krishna Myneni <krishna.myneni@ccreweb.org> wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior
    thread.

    Tests needed.

    ...

    These words should be in assembler anyway.
    So a rigorous testset is more valuable than a supposedly
    standard implementation.

    There is no standard implementation -- DLSHIFT and DRSHIFT are not
    standard words. What I meant by "standard source definitions" is that
    the Forth level definitions only use Forth standard words.

    Tests for my latest revision are provided.

    --
    KM


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Thu Mar 28 00:57:43 2024
    From Newsgroup: comp.lang.forth

    On 27/03/2024 10:26 pm, Ruvim wrote:
    On 2024-03-27 04:57, Krishna Myneni wrote:
    [...]
    We shouldn't have an ambiguous condition here because of some idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a single shift of `x` by `u` bits should always be equivalent to `u` sequential shifts by 1 bit.

    But neither the standard nor implementations follow this idea.

    The same occurred with 2/ and 2 / . Those who saw Forth as a language wanted consistent results; whereas those who saw Forth as a toolkit said give us what the hardware provides.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Ruvim@ruvim.pinka@gmail.com to comp.lang.forth on Wed Mar 27 18:56:54 2024
    From Newsgroup: comp.lang.forth

    On 2024-03-27 07:14, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior
    thread.
    ...

    This version fixes the issue with the ambiguity of LSHIFT and RSHIFT,
    and gives the behavior of DLSHIFT and DRSHIFT which I want. Tests
    included below for 32-bit and 64-bit systems.

    --
    KM

    === dshift.4th ===
    \ dshift.4th
    \
    \ Source code definitions of DLSHIFT and DRSHIFT

    1 cells 3 lshift constant BITS_PER_CELL
    BITS_PER_CELL 2* constant BITS_PER_DOUBLE

    \ Return the u least significant bits of cell value u1
    \ as the most significant bits of u2
    : lsbits ( u1 u -- u2 )
         BITS_PER_CELL min
         BITS_PER_CELL - negate
         lshift ;

    \ Return the u most significant bits of cell value u1
    \ as the least significant bits of u2
    : msbits ( u1 u -- u2 )
         BITS_PER_CELL min
         BITS_PER_CELL - negate
         rshift ;

    0 value ubits

    \ u is the number of bits to shift

    : DLSHIFT ( ud u -- ud2 )
        dup 0= IF drop EXIT THEN
        BITS_PER_DOUBLE min dup to ubits
        BITS_PER_CELL >= IF
          drop      \ high double has been left shifted out
          ubits BITS_PER_CELL -
          dup BITS_PER_CELL = IF
            2drop 0 0
          ELSE
            lshift 0 swap
          THEN
        ELSE
          ubits lshift swap
          dup >r
          ubits msbits or
          r> ubits lshift
          swap
        THEN ;

    : DRSHIFT ( ud u -- ud2 )
        dup 0= IF drop EXIT THEN
        BITS_PER_DOUBLE min dup to ubits
        BITS_PER_CELL >= IF
          nip    \ low double has been right shifted out
          ubits BITS_PER_CELL -
          dup BITS_PER_CELL = IF
            2drop 0 0
          ELSE
            rshift 0
          THEN
        ELSE
          swap ubits rshift
          swap dup >r
          ubits lsbits or
          r> ubits rshift
        THEN ;

    === End of dshift.4th ===




    I wrote a simpler implementation a long time ago. The file
    "double-shift.fth" below is a translation from [2] using different names
    for constants.


    === "double-shift.fth"

    :NONAME 0 -1 BEGIN DUP WHILE SWAP 1+ SWAP 1 RSHIFT REPEAT DROP ; EXECUTE CONSTANT BITS-PER-CELL

    BITS-PER-CELL 1- CONSTANT MAX-FOR-SHIFT1
    BITS-PER-CELL 2* 1- CONSTANT MAX-FOR-SHIFT2

    : (DLSHIFT) ( xd1 u -- xd2 )
    ( x.lo x.hi u )
    TUCK LSHIFT >R
    2DUP NEGATE BITS-PER-CELL + RSHIFT >R
    LSHIFT 2R> OR
    ;
    : DLSHIFT ( xd1 u -- xd2 )
    DUP 0= IF DROP EXIT THEN
    DUP MAX-FOR-SHIFT2 U> IF DROP 2DROP 0. EXIT THEN
    DUP MAX-FOR-SHIFT1 U> IF NIP BITS-PER-CELL - LSHIFT 0 SWAP EXIT THEN
    (DLSHIFT)
    ;
    : (DRSHIFT) ( xd1 u -- xd2 )
    ( x.lo x.hi u )
    2DUP RSHIFT >R
    TUCK NEGATE BITS-PER-CELL + LSHIFT >R
    RSHIFT R> OR R>
    ;
    : DRSHIFT ( xd1 u -- xd2 )
    DUP 0= IF DROP EXIT THEN
    DUP MAX-FOR-SHIFT2 U> IF DROP 2DROP 0. EXIT THEN
    DUP MAX-FOR-SHIFT1 U> IF >R NIP R> BITS-PER-CELL - RSHIFT 0 EXIT THEN
    (DRSHIFT)
    ;

    === End of "double-shift.fth"



    [2] Low-level definition for doubling cell size (in ForthML) <https://github.com/rufig/spf4-utf8/blob/master/devel/~pinka/model/forthproc/doubling-cell.f.xml>

    --
    Ruvim
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Wed Mar 27 10:33:17 2024
    From Newsgroup: comp.lang.forth

    On 3/27/24 09:56, Ruvim wrote:
    On 2024-03-27 07:14, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number
    left shift and right shift), over full shift range, per discussion in
    prior thread.
    ...
    ...

    I wrote a simpler implementation a long time ago. The file "double-shift.fth" below is a translation from [2] using different names
    for constants.


    === "double-shift.fth"

    :NONAME 0 -1 BEGIN DUP WHILE SWAP 1+ SWAP 1 RSHIFT REPEAT DROP ; EXECUTE CONSTANT BITS-PER-CELL

    BITS-PER-CELL 1-      CONSTANT MAX-FOR-SHIFT1
    BITS-PER-CELL 2* 1-   CONSTANT MAX-FOR-SHIFT2

    : (DLSHIFT) ( xd1 u -- xd2 )
      ( x.lo x.hi  u )
      TUCK LSHIFT >R
      2DUP NEGATE BITS-PER-CELL + RSHIFT >R
      LSHIFT 2R> OR
    ;
    : DLSHIFT ( xd1 u -- xd2 )
      DUP 0= IF  DROP EXIT THEN
      DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
      DUP MAX-FOR-SHIFT1 U> IF  NIP BITS-PER-CELL - LSHIFT 0 SWAP EXIT THEN
      (DLSHIFT)
    ;
    : (DRSHIFT) ( xd1 u -- xd2 )
      ( x.lo x.hi  u )
      2DUP RSHIFT >R
      TUCK NEGATE BITS-PER-CELL + LSHIFT >R
      RSHIFT R> OR R>
    ;
    : DRSHIFT ( xd1 u -- xd2 )
      DUP 0= IF  DROP EXIT THEN
      DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
      DUP MAX-FOR-SHIFT1 U> IF  >R NIP R> BITS-PER-CELL - RSHIFT 0 EXIT THEN
      (DRSHIFT)
    ;

    === End of "double-shift.fth"


    Does it succeed on all of the tests I gave?

    --
    Krishna


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Wed Mar 27 10:44:10 2024
    From Newsgroup: comp.lang.forth

    On 3/27/24 08:57, dxf wrote:
    On 27/03/2024 10:26 pm, Ruvim wrote:
    On 2024-03-27 04:57, Krishna Myneni wrote:
    [...]
    We shouldn't have an ambiguous condition here because of some idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.

    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a single shift of `x` by `u` bits should always be equivalent to `u` sequential shifts by 1 bit.

    But neither the standard nor implementations follow this idea.

    The same occurred with 2/ and 2 / . Those who saw Forth as a language wanted consistent results; whereas those who saw Forth as a toolkit said give us what
    the hardware provides.


    If one needs the machine shift instructions, they should be using the
    Forth assembler to write the word in which it is needed. The language specification has no justification (that I can see) for undefined
    behavior for the LSHIFT and RSHIFT instructions.

    --
    Krishna

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Ruvim@ruvim.pinka@gmail.com to comp.lang.forth on Wed Mar 27 20:36:43 2024
    From Newsgroup: comp.lang.forth

    On 2024-03-27 19:33, Krishna Myneni wrote:
    On 3/27/24 09:56, Ruvim wrote:
    On 2024-03-27 07:14, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number
    left shift and right shift), over full shift range, per discussion
    in prior thread.
    ...
    ...

    I wrote a simpler implementation a long time ago. The file
    "double-shift.fth" below is a translation from [2] using different
    names for constants.


    === "double-shift.fth"

    :NONAME 0 -1 BEGIN DUP WHILE SWAP 1+ SWAP 1 RSHIFT REPEAT DROP ; EXECUTE
    CONSTANT BITS-PER-CELL

    BITS-PER-CELL 1-      CONSTANT MAX-FOR-SHIFT1
    BITS-PER-CELL 2* 1-   CONSTANT MAX-FOR-SHIFT2

    : (DLSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       TUCK LSHIFT >R
       2DUP NEGATE BITS-PER-CELL + RSHIFT >R
       LSHIFT 2R> OR
    ;
    : DLSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  NIP BITS-PER-CELL - LSHIFT 0 SWAP EXIT THEN >>    (DLSHIFT)
    ;
    : (DRSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       2DUP RSHIFT >R
       TUCK NEGATE BITS-PER-CELL + LSHIFT >R
       RSHIFT R> OR R>
    ;
    : DRSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  >R NIP R> BITS-PER-CELL - RSHIFT 0 EXIT THEN >>    (DRSHIFT)
    ;

    === End of "double-shift.fth"


    Does it succeed on all of the tests I gave?

    Of course, I checked — it succeed your tests.


    --
    Ruvim

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Bernd Linsel@bl1-thispartdoesnotbelonghere@gmx.com to comp.lang.forth on Wed Mar 27 19:48:56 2024
    From Newsgroup: comp.lang.forth

    On 27.03.2024 13:28, Krishna Myneni wrote:

    I really think it is a bad idea to have UB in the spec of LSHIFT and
    RSHIFT due to the arbitrariness of low level shift operations at the
    hardware level.

    It's not UB, it is IB and thus it should be required that an implementer documents the respective behaviour of their system.

    Here we have a chance to remove that UB and guarantee that>
    1 BITS_PER_CELL LSHIFT  returns zero
    and
    1 BITS_PER_CELL RSHIFT  returns zero

    so that the expected result for a shift operation on the cell operand
    does not have UB.

    Efficiency because of extra instructions needed to implement this
    guarantee are not even worth bothering about -- we are not C.

    Forth does care about efficiency. Otherwise you could eliminate over the
    half of the ambiguous conditions in the Forth standard that only arise
    from the fact that hardware platforms differ in their behaviour.

    [snip]

    For the rare situation that a variable shift count is needed, and is not
    per se restricted to 0..ADDRESS-UNIT-BITS - 1, you can always write either

    0 MAX S" ADDRESS-UNIT-BITS" 1- MIN LSHIFT ( or RSHIFT)

    or

    DUP 0< INVERT IF DUP S" ADDRESS-UNIT-BITS" < IF LSHIFT ( or RSHIFT)
    ELSE ( whatever to do if shift-amount < 0)
    ELSE ( whatever to do if shift-amount >= cell width)
    THEN THEN

    or simply

    DUP 0< ABORT" shift amount less than 0"
    DUP S" ADDRESS-UNIT-BITS" 1- > ABORT" shift amount greater/equal cell width) LSHIFT ( or RSHIFT)



    NB: The behaviour of most processors to only regard the 5 or 6 LSBs is
    useful for expressions like -1 64 <n> - LSHIFT to produce bit masks,
    these can simply be expressed as <n> NEGATE LSHIFT (with an
    environmental dependency on processors that behave this way).
    --
    Bernd Linsel
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Bernd Linsel@bl1-thispartdoesnotbelonghere@gmx.com to comp.lang.forth on Wed Mar 27 19:50:46 2024
    From Newsgroup: comp.lang.forth

    On 27.03.2024 09:34, albert@spenarnc.xs4all.nl wrote:
    These words should be in assembler anyway.

    +1
    --
    Bernd Linsel
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Wed Mar 27 18:46:10 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    I really think it is a bad idea to have UB in the spec of LSHIFT and
    RSHIFT due to the arbitrariness of low level shift operations at the >hardware level. Here we have a chance to remove that UB and guarantee that

    1 BITS_PER_CELL LSHIFT returns zero
    and
    1 BITS_PER_CELL RSHIFT returns zero

    so that the expected result for a shift operation on the cell operand
    does not have UB.

    I guess you mean the ambiguous condition in the specification of
    LSHIFT and RSHIFT, which is more like implementation-defined behaviour
    in some other languages (and the advocates of undefined behaviour make
    a lot of wind about the difference between implementation-defined and undefined).

    Well, if you want to see this happen, you have to convince some Forth
    system implementors, so common practice moves in the direction you
    prefer, and once that is done, make a proposal.

    You could point out that the extra cost of the check is only incurred
    for shifts with non-constant shift amounts, and if you could provide
    data on the frequency of constant and non-constant shift amounts, this
    might help convince system implementors. Of course, for commercial implementors, you may get the usual answer that their customers have
    not complained to them, but if you don't try, you can't win.

    Efficiency because of extra instructions needed to implement this
    guarantee are not even worth bothering about -- we are not C.

    I am sure someone can produce some saying by Chuck Moore that
    contradicts this attitude. Sure, Forth is not C, but it's just as performance-conscious.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023: https://euro.theforth.net/2023
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Wed Mar 27 14:49:02 2024
    From Newsgroup: comp.lang.forth

    On 3/27/24 11:36, Ruvim wrote:

    === "double-shift.fth"

    :NONAME 0 -1 BEGIN DUP WHILE SWAP 1+ SWAP 1 RSHIFT REPEAT DROP ; EXECUTE >>> CONSTANT BITS-PER-CELL

    BITS-PER-CELL 1-      CONSTANT MAX-FOR-SHIFT1
    BITS-PER-CELL 2* 1-   CONSTANT MAX-FOR-SHIFT2

    : (DLSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       TUCK LSHIFT >R
       2DUP NEGATE BITS-PER-CELL + RSHIFT >R
       LSHIFT 2R> OR
    ;
    : DLSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  NIP BITS-PER-CELL - LSHIFT 0 SWAP EXIT THEN >>>    (DLSHIFT)
    ;
    : (DRSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       2DUP RSHIFT >R
       TUCK NEGATE BITS-PER-CELL + LSHIFT >R
       RSHIFT R> OR R>
    ;
    : DRSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  >R NIP R> BITS-PER-CELL - RSHIFT 0 EXIT >>> THEN
       (DRSHIFT)
    ;

    === End of "double-shift.fth"


    Does it succeed on all of the tests I gave?

    Of course, I checked — it succeed your tests.



    Thanks.

    -- KM


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Wed Mar 27 14:54:36 2024
    From Newsgroup: comp.lang.forth

    On 3/27/24 13:46, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    I really think it is a bad idea to have UB in the spec of LSHIFT and
    RSHIFT due to the arbitrariness of low level shift operations at the
    hardware level. Here we have a chance to remove that UB and guarantee that >>
    1 BITS_PER_CELL LSHIFT returns zero
    and
    1 BITS_PER_CELL RSHIFT returns zero

    so that the expected result for a shift operation on the cell operand
    does not have UB.

    I guess you mean the ambiguous condition in the specification of
    LSHIFT and RSHIFT, which is more like implementation-defined behaviour
    in some other languages (and the advocates of undefined behaviour make
    a lot of wind about the difference between implementation-defined and undefined).

    I have to admit that the distinction between mapping "ambiguous
    condition" to IB vs UB escapes me.


    Well, if you want to see this happen, you have to convince some Forth
    system implementors, so common practice moves in the direction you
    prefer, and once that is done, make a proposal.


    Sure. I would start with modifying LSHIFT and RSHIFT in my own Forth
    systems. The revisions would still be consistent with the standard.

    You could point out that the extra cost of the check is only incurred
    for shifts with non-constant shift amounts, and if you could provide
    data on the frequency of constant and non-constant shift amounts, this
    might help convince system implementors. Of course, for commercial implementors, you may get the usual answer that their customers have
    not complained to them, but if you don't try, you can't win.

    Efficiency because of extra instructions needed to implement this
    guarantee are not even worth bothering about -- we are not C.

    I am sure someone can produce some saying by Chuck Moore that
    contradicts this attitude. Sure, Forth is not C, but it's just as performance-conscious.


    My meaning was that I expect the performance change to be negligible. Of course, we have to implement and test to check this.

    --
    Krishna


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Thu Mar 28 08:06:15 2024
    From Newsgroup: comp.lang.forth

    May I ask for what you need these double cell shifts?

    I know of some crypto routines, but these require even much wider cell sizes.

    Another example: in my field pseudo random number generators are common technique.
    However PRNGs are closely related to prime numbers and they often require rotations of sub-cell chunks (linear feedback shift registers).
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Thu Mar 28 08:49:43 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On 3/27/24 13:46, Anton Ertl wrote:
    You could point out that the extra cost of the check is only incurred
    for shifts with non-constant shift amounts, and if you could provide
    data on the frequency of constant and non-constant shift amounts, this
    might help convince system implementors.

    Here's some data about the occurences in the Gforth image:

    Non-constant shift amount:
    2 lshift
    1 rshift
    0 arshift

    Constant shift amount:
    18 lit lshift
    41 lit rshift
    0 lit arshift

    Produced by inserting superinstructions for the constant shifts,
    rebuilding Gforth, and then

    gforth-fast --ss-states=0 --print-prims -e bye

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023: https://euro.theforth.net/2023
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Thu Mar 28 22:29:12 2024
    From Newsgroup: comp.lang.forth

    On 28/03/2024 2:44 am, Krishna Myneni wrote:
    On 3/27/24 08:57, dxf wrote:
    On 27/03/2024 10:26 pm, Ruvim wrote:
    On 2024-03-27 04:57, Krishna Myneni wrote:
    [...]
    We shouldn't have an ambiguous condition here because of some idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits. >>>
    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a single shift of `x` by `u` bits should always be equivalent to `u` sequential shifts by 1 bit.

    But neither the standard nor implementations follow this idea.

    The same occurred with 2/ and 2 / .  Those who saw Forth as a language wanted
    consistent results; whereas those who saw Forth as a toolkit said give us what
    the hardware provides.


    If one needs the machine shift instructions, they should be using the Forth assembler to write the word in which it is needed. The language specification has no justification (that I can see) for undefined behavior for the LSHIFT and RSHIFT instructions.

    Some 40 years ago Intel told their customers there's no justification for shifting
    a full cell of bits. ANS told the same thing to forthers.


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Thu Mar 28 08:10:46 2024
    From Newsgroup: comp.lang.forth

    On 3/28/24 03:06, minforth wrote:
    May I ask for what you need these double cell shifts?


    I'm interested in writing a portable IEEE 754 quad precision arithmetic library in Forth. The significands are 113 bits long, with implied bit included. To perform addition or subtraction between two quad precision numbers, the two significands have to be aligned using the difference in
    their base 2 exponents (15 bit exponents). This requires a relative
    shift of the two significands across a 128-bit representation of the two numbers being added/subtracted. On a 64-bit system, we can use double
    cell shifts to accomplish this.


    I know of some crypto routines, but these require even much wider cell sizes.

    Another example: in my field pseudo random number generators are common technique.
    However PRNGs are closely related to prime numbers and they often require rotations of sub-cell chunks (linear feedback shift registers).

    I'm sure there are a lot of other uses that I don't know about. Shifts registers came up during our previous discussion on SHA512 implementations.

    --
    Krishna


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Thu Mar 28 08:38:07 2024
    From Newsgroup: comp.lang.forth

    On 3/28/24 06:29, dxf wrote:
    On 28/03/2024 2:44 am, Krishna Myneni wrote:
    On 3/27/24 08:57, dxf wrote:
    On 27/03/2024 10:26 pm, Ruvim wrote:
    On 2024-03-27 04:57, Krishna Myneni wrote:
    [...]
    We shouldn't have an ambiguous condition here because of some idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits. >>>>
    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a single shift of `x` by `u` bits should always be equivalent to `u` sequential shifts by 1 bit.

    But neither the standard nor implementations follow this idea.

    The same occurred with 2/ and 2 / .  Those who saw Forth as a language wanted
    consistent results; whereas those who saw Forth as a toolkit said give us what
    the hardware provides.


    If one needs the machine shift instructions, they should be using the Forth assembler to write the word in which it is needed. The language specification has no justification (that I can see) for undefined behavior for the LSHIFT and RSHIFT instructions.

    Some 40 years ago Intel told their customers there's no justification for shifting
    a full cell of bits. ANS told the same thing to forthers.



    This really isn't an issue with the processor design -- they're under
    more severe constraints in what they can put in the hardware. The
    desired behavior can be achieved in software.

    When I first started programming in Forth, I appreciated the fact that
    it was close to the hardware. As processor speed and memory size and the complexity of my programs grew, and the need to share them as well, the cleanliness and portability of the language became more important.

    --
    Krishna



    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Thu Mar 28 14:25:45 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni wrote:

    On 3/28/24 03:06, minforth wrote:
    May I ask for what you need these double cell shifts?


    I'm interested in writing a portable IEEE 754 quad precision arithmetic library in Forth.

    Respect! Scaling is a basic fp operation indeed.

    You can test against libquadmath. For inspiration, browsing its source code might be of interest: https://codebrowser.dev/glibc/glibc/sysdeps/ieee754/float128/
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Fri Mar 29 11:23:34 2024
    From Newsgroup: comp.lang.forth

    On 29/03/2024 12:38 am, Krishna Myneni wrote:
    On 3/28/24 06:29, dxf wrote:
    On 28/03/2024 2:44 am, Krishna Myneni wrote:
    On 3/27/24 08:57, dxf wrote:
    On 27/03/2024 10:26 pm, Ruvim wrote:
    On 2024-03-27 04:57, Krishna Myneni wrote:
    [...]
    We shouldn't have an ambiguous condition here because of some idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits. >>>>>
    Ideally — yes.

    My rationale (see [1]) is that for any `x` and `u`, the result of a single shift of `x` by `u` bits should always be equivalent to `u` sequential shifts by 1 bit.

    But neither the standard nor implementations follow this idea.

    The same occurred with 2/ and 2 / .  Those who saw Forth as a language wanted
    consistent results; whereas those who saw Forth as a toolkit said give us what
    the hardware provides.


    If one needs the machine shift instructions, they should be using the Forth assembler to write the word in which it is needed. The language specification has no justification (that I can see) for undefined behavior for the LSHIFT and RSHIFT instructions.

    Some 40 years ago Intel told their customers there's no justification for shifting
    a full cell of bits.  ANS told the same thing to forthers.



    This really isn't an issue with the processor design -- they're under more severe constraints in what they can put in the hardware. The desired behavior can be achieved in software.

    If it's an issue of algorithm design - how many shifts does it take before a programmer
    realizes the result must be 0 - and should the language indulge him? If a forth programmer
    is determined that any shift count should work then he won't mind the performance loss of
    putting 2* or U2/ in a loop. Leave LSHIFT and RSHIFT to programmers whose goal is efficiency.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Mar 29 14:03:55 2024
    From Newsgroup: comp.lang.forth

    On 27-03-2024 01:57, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior
    thread.

    Tests needed.

    Just tested DLSHIFT and found weird things going on. Traced the problem
    to LSHIFT.

    Yep. That's why I had to create this horrible code in order to force the compiler to give me the behavior I want:

    CODE (SHIFT) DSIZE (2); a = DPOP;
    b = (sizeof (cell) * CHAR_BIT);
    if ((a < b) && (a > -b))
    { /* within cell size? */
    if (a < 0L)
    { /* force logical right shift */
    DS (1) = (DS (1) >> 1L) & CELL_MAX;
    a = -1L - a; DS (1) >>= a;
    } /* shift one bit, clear it */
    else DS (1) <<= a;
    } /* we're in zero territory now */
    else DS (1) = 0L;
    NEXT;

    Hans Bezemer

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Fri Mar 29 08:12:36 2024
    From Newsgroup: comp.lang.forth

    On 3/28/24 03:49, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On 3/27/24 13:46, Anton Ertl wrote:
    You could point out that the extra cost of the check is only incurred
    for shifts with non-constant shift amounts, and if you could provide
    data on the frequency of constant and non-constant shift amounts, this
    might help convince system implementors.

    Here's some data about the occurences in the Gforth image:

    Non-constant shift amount:
    2 lshift
    1 rshift
    0 arshift

    Constant shift amount:
    18 lit lshift
    41 lit rshift
    0 lit arshift

    ...

    Checking the Forth code base which I use, I find ~ 100:1 ratio between
    uses of constant shift amount to non-constant shifts. The existing
    instances of non-constant shifts are comparable to yours: two in number
    theory programs e.g., finding an exact fraction for a floating point
    number, and one use in the assembler.

    I don't know what to conclude from this other than the kind of
    application development I have been doing favors one over the other. The
    large number of constant shifts have to do with defining constants,
    largely for data acquisition interfaces.

    --
    Krishna




    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Mar 29 15:32:05 2024
    From Newsgroup: comp.lang.forth

    On 27-03-2024 20:49, Krishna Myneni wrote:
    On 3/27/24 11:36, Ruvim wrote:

    === "double-shift.fth"

    :NONAME 0 -1 BEGIN DUP WHILE SWAP 1+ SWAP 1 RSHIFT REPEAT DROP ;
    EXECUTE
    CONSTANT BITS-PER-CELL

    BITS-PER-CELL 1-      CONSTANT MAX-FOR-SHIFT1
    BITS-PER-CELL 2* 1-   CONSTANT MAX-FOR-SHIFT2

    : (DLSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       TUCK LSHIFT >R
       2DUP NEGATE BITS-PER-CELL + RSHIFT >R
       LSHIFT 2R> OR
    ;
    : DLSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  NIP BITS-PER-CELL - LSHIFT 0 SWAP EXIT >>>> THEN
       (DLSHIFT)
    ;
    : (DRSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       2DUP RSHIFT >R
       TUCK NEGATE BITS-PER-CELL + LSHIFT >R
       RSHIFT R> OR R>
    ;
    : DRSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  >R NIP R> BITS-PER-CELL - RSHIFT 0 EXIT >>>> THEN
       (DRSHIFT)
    ;

    === End of "double-shift.fth"

    Can't make it any shorter than this. And no idea what happens with less
    robust LSHIFT or RSHIFT implementations. CELL-BITS should be most
    obvious, : SPIN SWAP ROT ; should fix most porting issues, replace ;THEN
    with EXIT THEN. It passes all tests.

    : dlshift
    dup 0> 0= if drop ;then
    >r over 0 invert cell-bits r@ - dup >r lshift and r> rshift swap
    r@ lshift or swap r> lshift swap
    ;

    : drshift
    dup 0> 0= if drop ;then
    >r dup 0 invert cell-bits r@ - dup >r rshift and r> lshift swap
    r@ rshift spin r> rshift or swap
    ;

    Hans Bezemer
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Fri Mar 29 09:34:55 2024
    From Newsgroup: comp.lang.forth

    On 3/29/24 09:32, Hans Bezemer wrote:
    On 27-03-2024 20:49, Krishna Myneni wrote:
    On 3/27/24 11:36, Ruvim wrote:

    === "double-shift.fth"

    :NONAME 0 -1 BEGIN DUP WHILE SWAP 1+ SWAP 1 RSHIFT REPEAT DROP ;
    EXECUTE
    CONSTANT BITS-PER-CELL

    BITS-PER-CELL 1-      CONSTANT MAX-FOR-SHIFT1
    BITS-PER-CELL 2* 1-   CONSTANT MAX-FOR-SHIFT2

    : (DLSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       TUCK LSHIFT >R
       2DUP NEGATE BITS-PER-CELL + RSHIFT >R
       LSHIFT 2R> OR
    ;
    : DLSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  NIP BITS-PER-CELL - LSHIFT 0 SWAP EXIT >>>>> THEN
       (DLSHIFT)
    ;
    : (DRSHIFT) ( xd1 u -- xd2 )
       ( x.lo x.hi  u )
       2DUP RSHIFT >R
       TUCK NEGATE BITS-PER-CELL + LSHIFT >R
       RSHIFT R> OR R>
    ;
    : DRSHIFT ( xd1 u -- xd2 )
       DUP 0= IF  DROP EXIT THEN
       DUP MAX-FOR-SHIFT2 U> IF  DROP 2DROP 0. EXIT THEN
       DUP MAX-FOR-SHIFT1 U> IF  >R NIP R> BITS-PER-CELL - RSHIFT 0
    EXIT THEN
       (DRSHIFT)
    ;

    === End of "double-shift.fth"

    Can't make it any shorter than this. And no idea what happens with less robust LSHIFT or RSHIFT implementations. CELL-BITS should be most
    obvious, : SPIN SWAP ROT ; should fix most porting issues, replace ;THEN
    with EXIT THEN. It passes all tests.

    : dlshift
      dup 0> 0= if drop ;then
      >r over 0 invert cell-bits r@ - dup >r lshift and r> rshift swap
      r@ lshift or swap r> lshift swap
    ;

    : drshift
      dup 0> 0= if drop ;then
      >r dup 0 invert cell-bits r@ - dup >r rshift and r> lshift swap
      r@ rshift spin r> rshift or swap
    ;


    Thanks! I have updated LSHIFT and RSHIFT in kForth-32 and kForth-64 to
    handle shift count >= BITS_PER_CELL to give the expected answer (0).

    --
    Krishna



    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Fri Mar 29 09:41:08 2024
    From Newsgroup: comp.lang.forth

    On 3/26/24 19:57, Krishna Myneni wrote:
    On 3/26/24 17:01, Krishna Myneni wrote:
    Standard source definitions of DLSHIFT and DRSHIFT (double number left
    shift and right shift), over full shift range, per discussion in prior
    thread.

    Tests needed.

    Just tested DLSHIFT and found weird things going on. Traced the problem
    to LSHIFT.


    kforth64

    1 64 LSHIFT .  \ expected to get zero
    1              \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Gforth does the same thing

    1 64 LSHIFT .  1
    1 65 LSHIFT .  2
    etc.


    We shouldn't have an ambiguous condition here because of some
    idiosyncratic behavior of the SHL instruction!

    u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits.


    I have revised LSHIFT and RSHIFT in kForth-32 and kForth-64 to give
    expected results for shift count >= BITS_PER_CELL (still have to update kForth-Win32). Some test code to check that these words behave as expected:

    1 CELLS 8 * constant BITS_PER_CELL

    : test-lshift ( -- )
    BITS_PER_CELL 6 + 0 DO
    I 2 .R 2 SPACES
    1 I LSHIFT
    BINARY BITS_PER_CELL U.R CR DECIMAL
    LOOP ;

    : test-rshift ( -- )
    1 BITS_PER_CELL 1- LSHIFT
    BITS_PER_CELL 6 + 0 DO
    I 2 .R 2 SPACES
    DUP I RSHIFT
    BINARY BITS_PER_CELL U.R CR DECIMAL
    LOOP DROP ;

    TEST-LSHIFT ( on 32-bit system )
    0 1
    1 10
    2 100
    3 1000
    4 10000
    5 100000
    6 1000000
    7 10000000
    8 100000000
    9 1000000000
    10 10000000000
    11 100000000000
    12 1000000000000
    13 10000000000000
    14 100000000000000
    15 1000000000000000
    16 10000000000000000
    17 100000000000000000
    18 1000000000000000000
    19 10000000000000000000
    20 100000000000000000000
    21 1000000000000000000000
    22 10000000000000000000000
    23 100000000000000000000000
    24 1000000000000000000000000
    25 10000000000000000000000000
    26 100000000000000000000000000
    27 1000000000000000000000000000
    28 10000000000000000000000000000
    29 100000000000000000000000000000
    30 1000000000000000000000000000000
    31 10000000000000000000000000000000
    32 0
    33 0
    34 0
    35 0
    36 0
    37 0
    ok
    TEST-RSHIFT ( on 32-bit system )
    0 10000000000000000000000000000000
    1 1000000000000000000000000000000
    2 100000000000000000000000000000
    3 10000000000000000000000000000
    4 1000000000000000000000000000
    5 100000000000000000000000000
    6 10000000000000000000000000
    7 1000000000000000000000000
    8 100000000000000000000000
    9 10000000000000000000000
    10 1000000000000000000000
    11 100000000000000000000
    12 10000000000000000000
    13 1000000000000000000
    14 100000000000000000
    15 10000000000000000
    16 1000000000000000
    17 100000000000000
    18 10000000000000
    19 1000000000000
    20 100000000000
    21 10000000000
    22 1000000000
    23 100000000
    24 10000000
    25 1000000
    26 100000
    27 10000
    28 1000
    29 100
    30 10
    31 1
    32 0
    33 0
    34 0
    35 0
    36 0
    37 0
    ok

    Similar displays for 64-bit systems.

    --
    KM


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Fri Mar 29 16:55:32 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On 3/28/24 03:49, Anton Ertl wrote:
    Here's some data about the occurences in the Gforth image:

    Non-constant shift amount:
    2 lshift
    1 rshift
    0 arshift

    Constant shift amount:
    18 lit lshift
    41 lit rshift
    0 lit arshift

    ...

    Checking the Forth code base which I use, I find ~ 100:1 ratio between
    uses of constant shift amount to non-constant shifts. The existing
    instances of non-constant shifts are comparable to yours: two in number >theory programs e.g., finding an exact fraction for a floating point
    number, and one use in the assembler.

    I don't know what to conclude from this other than the kind of
    application development I have been doing favors one over the other.

    It shows that Forth systems that support special code generation for
    operations with constants (probably all native-code systems, as well
    as Gforth) would be able to generate the same code in the vast
    majority of cases even with the change you propose. Only in the few non-constant cases a few extra instructions would be needed.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023: https://euro.theforth.net/2023
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Mar 30 12:04:05 2024
    From Newsgroup: comp.lang.forth

    On 28/03/2024 3:36 am, Ruvim wrote:
    On 2024-03-27 19:33, Krishna Myneni wrote:
    ...
    Does it succeed on all of the tests I gave?

    Of course, I checked — it succeed your tests.

    VFX's implementations are simpler still and pass the tests with the
    exception of 5 and 6 (same ambiguous conditions as ANS).




    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Sat Mar 30 07:58:34 2024
    From Newsgroup: comp.lang.forth

    On 3/29/24 11:55, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On 3/28/24 03:49, Anton Ertl wrote:
    Here's some data about the occurences in the Gforth image:

    Non-constant shift amount:
    2 lshift
    1 rshift
    0 arshift

    Constant shift amount:
    18 lit lshift
    41 lit rshift
    0 lit arshift

    ...

    Checking the Forth code base which I use, I find ~ 100:1 ratio between
    uses of constant shift amount to non-constant shifts. The existing
    instances of non-constant shifts are comparable to yours: two in number
    theory programs e.g., finding an exact fraction for a floating point
    number, and one use in the assembler.

    I don't know what to conclude from this other than the kind of
    application development I have been doing favors one over the other.

    It shows that Forth systems that support special code generation for operations with constants (probably all native-code systems, as well
    as Gforth) would be able to generate the same code in the vast
    majority of cases even with the change you propose. Only in the few non-constant cases a few extra instructions would be needed.


    Ah, so optimizing Forth compilers can do a compile-time check for
    literal shifts and not have to insert instructions for compare and
    branch e.g., my new implementation of LSHIFT in kforth64

    (from vm64-common.s)

    .equ MAX_SHIFT_COUNT, WSIZE*8-1

    L_lshift:
    LDSP
    DROP
    mov (%rbx), %rcx
    cmp $MAX_SHIFT_COUNT, %rcx
    jbe lshift1
    movq $0, WSIZE(%rbx)
    NEXT
    lshift1:
    shlq %cl, WSIZE(%rbx)
    NEXT


    The older version was:

    L_lshift:
    LDSP
    DROP
    mov (%rbx), %rcx
    shlq %cl, WSIZE(%rbx)
    NEXT

    Similarly for RSHIFT.

    --
    KM

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Mar 30 17:29:04 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    Ah, so optimizing Forth compilers can do a compile-time check for
    literal shifts and not have to insert instructions for compare and
    branch

    Yes.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023: https://euro.theforth.net/2023
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Mar 31 12:24:05 2024
    From Newsgroup: comp.lang.forth

    On 30/03/2024 1:32 am, Hans Bezemer wrote:
    ...
    And no idea what happens with less robust LSHIFT or RSHIFT implementations.

    Simply define:

    : lshift dup cell-bits u< 0= abort" **shift-arg**" lshift ;
    : rshift dup cell-bits u< 0= abort" **shift-arg**" rshift ;

    It will reveal all the out-of-bounds cases in one's code that's been masked
    by having LSHIFT and RSHIFT return zero.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Apr 1 12:22:18 2024
    From Newsgroup: comp.lang.forth

    On 30/03/2024 1:32 am, Hans Bezemer wrote:
    ...
    Can't make it any shorter than this. And no idea what happens with less robust LSHIFT or RSHIFT implementations. CELL-BITS should be most obvious, : SPIN SWAP ROT ; should fix most porting issues, replace ;THEN
    with EXIT THEN. It passes all tests.

    : dlshift
      dup 0> 0= if drop ;then
      >r over 0 invert cell-bits r@ - dup >r lshift and r> rshift swap
      r@ lshift or swap r> lshift swap
    ;

    : drshift
      dup 0> 0= if drop ;then
      >r dup 0 invert cell-bits r@ - dup >r rshift and r> lshift swap
      r@ rshift spin r> rshift or swap
    ;

    The table below shows the arguments (number and shift) presented to each RSHIFT/LSHIFT in your double-shift algorithm using the 9 tests Krishna provided.

    I've used a 32-bit forth in which RSHIFT/LSHIFT have been modified such that shifts greater than 31 bits will return 0 per the 'no ambiguous conditions' recommendation.

    -1 0 3 0 1 20 3 20 00 03

    -1 0 FF 0 0 20 FF 20 00 FF

    -1 0 1 0 1 20 0 20 01 00

    -1 0 FF 0 FF 20 0 20 FF 00

    -1 -20 0 -20 -1 40 -1 40 00 00

    -1 -20 0 -20 -1 40 -1 40 00 00

    -1 1 2 1 1 1F 3 1F

    -1 1F -80000000 1F 2 1 -80000000 1

    -1 1F 1 1F 3 1 7 1

    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me. That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic. IMO it were better that RSHIFT/LSHIFT should fail than
    do this.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Mon Apr 1 08:03:56 2024
    From Newsgroup: comp.lang.forth

    dxf wrote:

    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me. That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic. IMO it were better that RSHIFT/LSHIFT should fail than
    do this.

    Doesn't make sense during fp number addition/subtraction.
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Apr 1 20:21:23 2024
    From Newsgroup: comp.lang.forth

    On 1/04/2024 7:03 pm, minforth wrote:
    dxf wrote:

    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me.  That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic.  IMO it were better that RSHIFT/LSHIFT should fail than
    do this.

    Doesn't make sense during fp number addition/subtraction.

    Example?

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Mon Apr 1 11:35:05 2024
    From Newsgroup: comp.lang.forth

    In article <uu1pmo$305br$1@dont-email.me>,
    Bernd Linsel <bl1-thispartdoesnotbelonghere@gmx.com> wrote:
    On 27.03.2024 13:28, Krishna Myneni wrote:

    I really think it is a bad idea to have UB in the spec of LSHIFT and
    RSHIFT due to the arbitrariness of low level shift operations at the
    hardware level.

    It's not UB, it is IB and thus it should be required that an implementer >documents the respective behaviour of their system.

    Here we have a chance to remove that UB and guarantee that>
    1 BITS_PER_CELL LSHIFT  returns zero
    and
    1 BITS_PER_CELL RSHIFT  returns zero

    so that the expected result for a shift operation on the cell operand
    does not have UB.

    Efficiency because of extra instructions needed to implement this
    guarantee are not even worth bothering about -- we are not C.

    Forth does care about efficiency. Otherwise you could eliminate over the
    half of the ambiguous conditions in the Forth standard that only arise
    from the fact that hardware platforms differ in their behaviour.

    [snip]

    For the rare situation that a variable shift count is needed, and is not
    per se restricted to 0..ADDRESS-UNIT-BITS - 1, you can always write either

    0 MAX S" ADDRESS-UNIT-BITS" 1- MIN LSHIFT ( or RSHIFT)

    or

    DUP 0< INVERT IF DUP S" ADDRESS-UNIT-BITS" < IF LSHIFT ( or RSHIFT)
    ELSE ( whatever to do if shift-amount < 0)
    ELSE ( whatever to do if shift-amount >= cell width)
    THEN THEN

    or simply

    DUP 0< ABORT" shift amount less than 0"
    DUP S" ADDRESS-UNIT-BITS" 1- > ABORT" shift amount greater/equal cell width) >LSHIFT ( or RSHIFT)

    I hate ABORT in this context. Are you sure that you want to shut down
    the nuclear power plant in this situation?


    NB: The behaviour of most processors to only regard the 5 or 6 LSBs is
    useful for expressions like -1 64 <n> - LSHIFT to produce bit masks,
    these can simply be expressed as <n> NEGATE LSHIFT (with an
    environmental dependency on processors that behave this way).


    --
    Bernd Linsel
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat purring. - the Wise from Antrim -
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Mon Apr 1 09:56:59 2024
    From Newsgroup: comp.lang.forth

    albert@spenarnc.xs4all.nl writes:
    In article <uu1pmo$305br$1@dont-email.me>,
    Bernd Linsel <bl1-thispartdoesnotbelonghere@gmx.com> wrote:
    NB: The behaviour of most processors to only regard the 5 or 6 LSBs is >>useful for expressions like -1 64 <n> - LSHIFT to produce bit masks,
    these can simply be expressed as <n> NEGATE LSHIFT (with an
    environmental dependency on processors that behave this way).

    Let's see:

    -1 64 2 - lshift hex. $C000000000000000 ok
    -1 64 1 - lshift hex. $8000000000000000 ok
    -1 64 0 - lshift hex. $FFFFFFFFFFFFFFFF ok

    I have my doubts that somebody performing such a computation intends
    to produce the last result. A result of 0 is more likely to be
    intended. Of course, there is some chance that providing a zero <n>
    for that computation is not intended, which may be a justification for everybody involved to produce arbitrary results in that case.

    Anyway, given 64-bt cells, the standard LSHIFT and twos-complement
    arithmetic (which is assumed by the "-1" above already), one can
    express the intention as follows:

    : gen-mask1 ( n -- x )
    \ produce -1 if <n>=0
    negate 63 and -1 swap lshift ;

    : gen-mask2 ( n -- x )
    \ produce 0 if <n>=0
    64 swap - dup 64 u< if
    -1 swap lshift
    else
    drop 0
    then ;

    : gen-mask3 ( n -- x )
    \ throw if <n>=0
    64 swap - dup 64 u< 0= -24 and throw -1 swap lshift ;

    And similarly for machine code. So, if GEN-MASK1 is intended, even an
    LSHIFT that produces 0 for larger shift counts is only one instruction
    away. So it is unlikely that the computer architects decided to look
    at only the LSB bits for that purpose.

    BTW, I ignore base64-encoded postings.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023: https://euro.theforth.net/2023
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Mon Apr 1 17:18:16 2024
    From Newsgroup: comp.lang.forth

    On 01-04-2024 03:22, dxf wrote:
    On 30/03/2024 1:32 am, Hans Bezemer wrote:
    ...
    Can't make it any shorter than this. And no idea what happens with less robust LSHIFT or RSHIFT implementations. CELL-BITS should be most obvious, : SPIN SWAP ROT ; should fix most porting issues, replace ;THEN
    with EXIT THEN. It passes all tests.

    : dlshift
      dup 0> 0= if drop ;then
      >r over 0 invert cell-bits r@ - dup >r lshift and r> rshift swap
      r@ lshift or swap r> lshift swap
    ;

    : drshift
      dup 0> 0= if drop ;then
      >r dup 0 invert cell-bits r@ - dup >r rshift and r> lshift swap
      r@ rshift spin r> rshift or swap
    ;

    The table below shows the arguments (number and shift) presented to each RSHIFT/LSHIFT in your double-shift algorithm using the 9 tests Krishna provided.

    I've used a 32-bit forth in which RSHIFT/LSHIFT have been modified such that shifts greater than 31 bits will return 0 per the 'no ambiguous conditions' recommendation.

    -1 0 3 0 1 20 3 20 00 03

    -1 0 FF 0 0 20 FF 20 00 FF

    -1 0 1 0 1 20 0 20 01 00

    -1 0 FF 0 FF 20 0 20 FF 00

    -1 -20 0 -20 -1 40 -1 40 00 00

    -1 -20 0 -20 -1 40 -1 40 00 00

    -1 1 2 1 1 1F 3 1F

    -1 1F -80000000 1F 2 1 -80000000 1

    -1 1F 1 1F 3 1 7 1

    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me. That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic. IMO it were better that RSHIFT/LSHIFT should fail than
    do this.
    I see where you're going with this. I have two things to say about this:
    1. If you're confronted with a LSHIFT/RSHIFT that's not reliable when
    you exceed a CELL-BITS shift, the entire discussion is moot anyway;
    2. 4tH's implementation does not have a separate LSHIFT/RSHIFT. It's the
    same thing, so a negative shift works as expected.

    That may seem a bit harsh, but it's the consequence of "An ambiguous
    condition exists if u is greater than or equal to the number of bits in
    a cell" and a separate LSHIFT and RSHIFT. I mean a MAX-U shift is
    meaningless in every universe (spoiler alert: it's "ambiguous"), why not
    make it "+/-n"?

    The only viable alternative is:

    : DLSHIFT ( xd1 n -- xd2) 0 ?do d2* loop ;
    : DRSHIFT ( xd1 n -- xd2) 0 ?do d2/ loop ;

    Which is okay in my book, but may be not fast enough for some.

    One could save the routine by adding:
    dup cell-bits - dup 0< 0= if abs >r >r swap dup xor r> r> swap then drop

    Sure, it wont be any faster, but it'd avoid "ambiguous" LSHIFT/RSHIFT
    issues.

    Hans Bezemer



    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Mon Apr 1 17:53:59 2024
    From Newsgroup: comp.lang.forth

    On 01-04-2024 03:22, dxf wrote:
    On 30/03/2024 1:32 am, Hans Bezemer wrote:
    ...
    Can't make it any shorter than this. And no idea what happens with less robust LSHIFT or RSHIFT implementations. CELL-BITS should be most obvious, : SPIN SWAP ROT ; should fix most porting issues, replace ;THEN
    with EXIT THEN. It passes all tests.

    : dlshift
      dup 0> 0= if drop ;then
      >r over 0 invert cell-bits r@ - dup >r lshift and r> rshift swap
      r@ lshift or swap r> lshift swap
    ;

    : drshift
      dup 0> 0= if drop ;then
      >r dup 0 invert cell-bits r@ - dup >r rshift and r> lshift swap
      r@ rshift spin r> rshift or swap
    ;

    The table below shows the arguments (number and shift) presented to each RSHIFT/LSHIFT in your double-shift algorithm using the 9 tests Krishna provided.

    I've used a 32-bit forth in which RSHIFT/LSHIFT have been modified such that shifts greater than 31 bits will return 0 per the 'no ambiguous conditions' recommendation.

    -1 0 3 0 1 20 3 20 00 03

    -1 0 FF 0 0 20 FF 20 00 FF

    -1 0 1 0 1 20 0 20 01 00

    -1 0 FF 0 FF 20 0 20 FF 00

    -1 -20 0 -20 -1 40 -1 40 00 00

    -1 -20 0 -20 -1 40 -1 40 00 00

    -1 1 2 1 1 1F 3 1F

    -1 1F -80000000 1F 2 1 -80000000 1

    -1 1F 1 1F 3 1 7 1

    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me. That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic. IMO it were better that RSHIFT/LSHIFT should fail than
    do this.

    This should fix it with minimal overhead:

    RSHIFT: dup cell-bits - dup 0< 0= if >r drop nip r> rshift 0 swap ;then drop LSHIFT: dup cell-bits - dup 0< 0= if >r drop drop r> lshift 0 ;then drop

    Moderately tested.

    Hans Bezemer

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Mon Apr 1 18:03:03 2024
    From Newsgroup: comp.lang.forth

    On 01-04-2024 17:53, Hans Bezemer wrote:
    On 01-04-2024 03:22, dxf wrote:
    On 30/03/2024 1:32 am, Hans Bezemer wrote:
    ...
    Can't make it any shorter than this. And no idea what happens with
    less robust LSHIFT or RSHIFT implementations. CELL-BITS should be
    most obvious, : SPIN SWAP ROT ; should fix most porting issues,
    replace ;THEN
    with EXIT THEN. It passes all tests.

    : dlshift
       dup 0> 0= if drop ;then
       >r over 0 invert cell-bits r@ - dup >r lshift and r> rshift swap
       r@ lshift or swap r> lshift swap
    ;

    : drshift
       dup 0> 0= if drop ;then
       >r dup 0 invert cell-bits r@ - dup >r rshift and r> lshift swap
       r@ rshift spin r> rshift or swap
    ;

    The table below shows the arguments (number and shift) presented to each
    RSHIFT/LSHIFT in your double-shift algorithm using the 9 tests Krishna
    provided.

    I've used a 32-bit forth in which RSHIFT/LSHIFT have been modified
    such that
    shifts greater than 31 bits will return 0 per the 'no ambiguous
    conditions'
    recommendation.

    -1 0   3 0   1 20   3 20   00 03

    -1 0   FF 0   0  20   FF 20   00 FF

    -1 0   1  0   1  20   0  20   01 00

    -1 0   FF 0   FF 20   0  20   FF 00

    -1 -20   0 -20   -1 40   -1 40   00 00

    -1 -20   0 -20   -1 40   -1 40   00 00

    -1 1   2 1   1 1F   3 1F

    -1 1F   -80000000 1F   2 1   -80000000 1

    -1 1F   1 1F   3 1   7 1

    While your double-shift algorithm produces the correct results (not
    shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite
    out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me.  That
    an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a
    result of 0,
    I for one find problematic.  IMO it were better that RSHIFT/LSHIFT
    should fail than
    do this.

    This should fix it with minimal overhead:

    RSHIFT: dup cell-bits - dup 0< 0= if >r drop nip r> rshift 0 swap ;then
    drop
    LSHIFT: dup cell-bits - dup 0< 0= if >r drop drop r> lshift 0 ;then drop

    Moderately tested.

    Hans Bezemer


    Darn, scrap that:

    RSHIFT: dup cell-bits - dup 0< 0= if >r drop nip r> rshift 0 ;then drop
    LSHIFT: dup cell-bits - dup 0< 0= if >r drop drop r> lshift 0 swap ;then
    drop

    Hans Bezemer

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Mon Apr 1 19:56:52 2024
    From Newsgroup: comp.lang.forth

    On 4/1/24 10:18, Hans Bezemer wrote:
    ...
    The only viable alternative is:

    : DLSHIFT  ( xd1 n -- xd2)     0 ?do d2* loop ;
    : DRSHIFT  ( xd1 n -- xd2)     0 ?do d2/ loop ;


    DRSHIFT cannot be coded with D2/ which is an arithmetic right shift,
    i.e. it preserves the sign bit. DRSHIFT has to pad from the left with
    zero bits.

    --
    Krishna


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Mon Apr 1 20:35:12 2024
    From Newsgroup: comp.lang.forth

    On 4/1/24 04:21, dxf wrote:
    On 1/04/2024 7:03 pm, minforth wrote:
    dxf wrote:

    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me.  That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic.  IMO it were better that RSHIFT/LSHIFT should fail than
    do this.

    Doesn't make sense during fp number addition/subtraction.

    Example?


    First, there is no negative shift count argument for LSHIFT RSHIFT
    DLSHIFT or DRSHIFT . The arguments are unsigned.

    For an ieee 754 double precision number, there is an effective distance
    of 53 bits between the most significant bit and the least significant
    bit. On a 32-bit system, consider adding 1.0e0 to the number 1.0e10.

    The ieee-754 unbiased base 2 exponents for the two floating point
    arguments are 0 (for 1.0e0) and 33 (for 1.0e10). This means that adding
    the two 53-bit significands using two double numbers (two 64-bit numbers
    on a 32 bit system) requires a relative right shift of 33 bits for the argument 1.0e0.

    Here are the bit patterns for the two significands, along with their
    base 2 exponents:

    21098765432109876543210987654321098765432109876543210 10010101000000101111100100000000000000000000000000000 33 10000000000000000000000000000000000000000000000000000 00

    There are 53 bits in each significand, and the 53rd bit is always an
    implied 1. To add these, we can use 33 DRSHIFT on the one argument to
    align the significands and add the two double length numbers to obtain
    the new significand.

    For ieee 754 quad precision, there are 113 bits in the significand, so relative shifts can be as large as 112 bits for addition and subtraction.

    --
    Krishna

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Tue Apr 2 10:56:26 2024
    From Newsgroup: comp.lang.forth

    On 02-04-2024 02:56, Krishna Myneni wrote:
    On 4/1/24 10:18, Hans Bezemer wrote:
    ...
    The only viable alternative is:

    : DLSHIFT  ( xd1 n -- xd2)     0 ?do d2* loop ;
    : DRSHIFT  ( xd1 n -- xd2)     0 ?do d2/ loop ;


    DRSHIFT cannot be coded with D2/ which is an arithmetic right shift,
    i.e. it preserves the sign bit. DRSHIFT has to pad from the left with
    zero bits.

    True, but if you know my coding style - this is not it. And it is
    acknowledged as such in the source:

    \ DXForth MISC.SCR, Copyright Ed, 2011-03-25
    \ Albert van der Horst, Thursday 09 April 2015 19:57:13, c.l.f

    So it's not uncommon to define it like this. Apart from that - "D2/" is
    not a standardized word - so it can mean anything. Although I do agree
    with you that your definition is the most likely one.

    Hans Bezemer
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Tue Apr 2 06:33:46 2024
    From Newsgroup: comp.lang.forth

    On 4/2/24 03:56, Hans Bezemer wrote:
    On 02-04-2024 02:56, Krishna Myneni wrote:
    On 4/1/24 10:18, Hans Bezemer wrote:
    ...
    The only viable alternative is:

    : DLSHIFT  ( xd1 n -- xd2)     0 ?do d2* loop ;
    : DRSHIFT  ( xd1 n -- xd2)     0 ?do d2/ loop ;


    DRSHIFT cannot be coded with D2/ which is an arithmetic right shift,
    i.e. it preserves the sign bit. DRSHIFT has to pad from the left with
    zero bits.

    True, but if you know my coding style - this is not it. And it is acknowledged as such in the source:

    \ DXForth MISC.SCR, Copyright Ed, 2011-03-25
    \ Albert van der Horst, Thursday 09 April 2015 19:57:13, c.l.f

    So it's not uncommon to define it like this. Apart from that - "D2/" is
    not a standardized word - so it can mean anything. Although I do agree
    with you that your definition is the most likely one.

    Hans Bezemer

    D2/ is a standardized word, since ANS Forth:

    8.6.1.1100
    D2/
    “d-two-slash”
    DOUBLE
    ( xd1 – – xd2 )
    xd2 is the result of shifting xd1 one bit toward the least-significant
    bit, leaving the most-significant bit unchanged.

    --
    KM

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Tue Apr 2 16:10:04 2024
    From Newsgroup: comp.lang.forth

    On 02-04-2024 13:33, Krishna Myneni wrote:
    On 4/2/24 03:56, Hans Bezemer wrote:
    On 02-04-2024 02:56, Krishna Myneni wrote:
    On 4/1/24 10:18, Hans Bezemer wrote:
    ...
    The only viable alternative is:

    : DLSHIFT  ( xd1 n -- xd2)     0 ?do d2* loop ;
    : DRSHIFT  ( xd1 n -- xd2)     0 ?do d2/ loop ;


    DRSHIFT cannot be coded with D2/ which is an arithmetic right shift,
    i.e. it preserves the sign bit. DRSHIFT has to pad from the left with
    zero bits.

    True, but if you know my coding style - this is not it. And it is
    acknowledged as such in the source:

    \ DXForth MISC.SCR, Copyright Ed, 2011-03-25
    \ Albert van der Horst, Thursday 09 April 2015 19:57:13, c.l.f

    So it's not uncommon to define it like this. Apart from that - "D2/"
    is not a standardized word - so it can mean anything. Although I do
    agree with you that your definition is the most likely one.

    Hans Bezemer

    D2/ is a standardized word, since ANS Forth:

    8.6.1.1100
    D2/
    “d-two-slash”
    DOUBLE
    ( xd1 – – xd2 )
    xd2 is the result of shifting xd1 one bit toward the least-significant
    bit, leaving the most-significant bit unchanged.

    I stand corrected, sir. ;-)

    Hans Bezemer

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Thu Apr 4 18:42:07 2024
    From Newsgroup: comp.lang.forth

    On 2/04/2024 2:02 pm, dxf wrote:
    ...
    LSHIFT/RSHIFT was intended to support the corresponding machine-code primitives available on
    modern architectures.

    Not a bad guess as it turns out.

    Digging further I found this from ANS 'BASIS17' June 1991:

    8.1.2205 SHIFT

    ( x1 n -- x2 )

    Perform a logical shift of n bit-places on x1, giving x2. If n is
    positive, shift the bits n places toward the most significant bit. If n is
    negative, shift them toward the least significant bits. Put zero into
    the places "uncovered" by the shift.

    That led to this Jan 1992 message:

    https://groups.google.com/g/comp.lang.forth/c/DqrKMIiyLWc/m/1XUyYBaHyfYJ

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Thu Apr 4 17:34:27 2024
    From Newsgroup: comp.lang.forth

    On 04-04-2024 09:42, dxf wrote:
    On 2/04/2024 2:02 pm, dxf wrote:
    ...
    LSHIFT/RSHIFT was intended to support the corresponding machine-code primitives available on
    modern architectures.

    Not a bad guess as it turns out.

    Digging further I found this from ANS 'BASIS17' June 1991:

    8.1.2205 SHIFT

    ( x1 n -- x2 )

    Perform a logical shift of n bit-places on x1, giving x2. If n is
    positive, shift the bits n places toward the most significant bit. If n is
    negative, shift them toward the least significant bits. Put zero into
    the places "uncovered" by the shift.

    That led to this Jan 1992 message:

    https://groups.google.com/g/comp.lang.forth/c/DqrKMIiyLWc/m/1XUyYBaHyfYJ

    Fun part - 4tH still has SHIFT, performing exactly as indicated. LSHIFT
    is exactly like SHIFT, while RSHIFT is expanded to NEGATE SHIFT.

    It's been like that for the last 30 years. Can't remember whether I
    nicked the word from Forth-79, but if it was there I can't rule it out.

    The word has been changed several times. First to force a logical RSHIFT
    and second to properly handle shifts exceeding CELL-BITS bits.

    It's also exposed in uBasic/4tH with the SHL() function (which also
    accepts negative shifts).

    Hans Bezemer
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Thu Apr 4 16:27:25 2024
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    That led to this Jan 1992 message:

    https://groups.google.com/g/comp.lang.forth/c/DqrKMIiyLWc/m/1XUyYBaHyfYJ

    I found the last posting in this thread most fitting:

    |Andrew Scott
    |Jan 13, 1992, 9:32:24 PM
    |
    |John Hayes writes:
    The bidirectional shift operator is probably a result of the parsimony
    of Forth philosophy; why have two operators when one will do.
    |
    |I thought part of the Forth philosophy was exactly the *opposite*. We |wouldn't have words like 1+ or 0< if efficiency wasn't regarded as more |important than a small set of consistent words.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023: https://euro.theforth.net/2023
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Fri Apr 5 11:58:39 2024
    From Newsgroup: comp.lang.forth

    On 5/04/2024 2:34 am, Hans Bezemer wrote:
    On 04-04-2024 09:42, dxf wrote:
    On 2/04/2024 2:02 pm, dxf wrote:
    ...
    LSHIFT/RSHIFT was intended to support the corresponding machine-code primitives available on
    modern architectures.

    Not a bad guess as it turns out.

    Digging further I found this from ANS 'BASIS17' June 1991:

       8.1.2205 SHIFT

         ( x1 n -- x2 )

       Perform a logical shift of n bit-places on x1, giving x2. If n is
       positive, shift the bits n places toward the most significant bit. If n is
       negative, shift them toward the least significant bits. Put zero into >>    the places "uncovered" by the shift.

    That led to this Jan 1992 message:

    https://groups.google.com/g/comp.lang.forth/c/DqrKMIiyLWc/m/1XUyYBaHyfYJ

    Fun part - 4tH still has SHIFT, performing exactly as indicated. LSHIFT is exactly like SHIFT, while RSHIFT is expanded to NEGATE SHIFT.

    It's been like that for the last 30 years. Can't remember whether I nicked the word from Forth-79, but if it was there I can't rule it out.

    Didn't think to look but yes - it is from Forth-79 'Reference Word Set' (Kitt Peak Forth
    words that didn't make it into the standard proper).

    ASHIFT n1 n2 -- n3
    Shift the value n1 arithemetically n2 bits left if n2 is
    positive, shifting zeros into the least-significant bit
    positions. If n2 is negative, n1 is shifted right. Sign
    extension is to be consistent with the processor's arithmetic
    shift.

    The word has been changed several times. First to force a logical RSHIFT and second to properly handle shifts exceeding CELL-BITS bits.

    It's also exposed in uBasic/4tH with the SHL() function (which also accepts negative shifts).

    Hans Bezemer

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Apr 5 22:43:52 2024
    From Newsgroup: comp.lang.forth

    On 04-04-2024 18:27, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    I found the last posting in this thread most fitting:

    |Andrew Scott
    |Jan 13, 1992, 9:32:24 PM
    |
    |John Hayes writes:
    The bidirectional shift operator is probably a result of the parsimony
    of Forth philosophy; why have two operators when one will do.
    |
    |I thought part of the Forth philosophy was exactly the *opposite*. We |wouldn't have words like 1+ or 0< if efficiency wasn't regarded as more |important than a small set of consistent words.

    So true - which is fun when you're implementing Forth in bytecode. Since bytecodes are limited, you want to restrict the number of words, while
    Forth tends to expand its vocabulary. The most common ones have their
    own bytecode in 4tH, while the less frequently used are often
    composites. 4tH got about 100 bytecodes, but almost three times the
    number of builtin words.

    Hans Bezemer

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Apr 6 12:11:36 2024
    From Newsgroup: comp.lang.forth

    On 5/04/2024 3:27 am, Anton Ertl wrote:
    ...
    I found the last posting in this thread most fitting:

    |Andrew Scott
    |Jan 13, 1992, 9:32:24 PM
    |
    |John Hayes writes:
    The bidirectional shift operator is probably a result of the parsimony
    of Forth philosophy; why have two operators when one will do.
    |
    |I thought part of the Forth philosophy was exactly the *opposite*. We |wouldn't have words like 1+ or 0< if efficiency wasn't regarded as more |important than a small set of consistent words.

    ALLOT is a good example of the 'parsimony' rule. Unlike bidirectional
    shift, co-habitation is cheap and easy. Issues created by a bidirectional ALLOT mostly affects 16-bit users. As I could afford to be single, I have ALLOT and RECOVER.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Sun Apr 7 14:53:12 2024
    From Newsgroup: comp.lang.forth

    On 01-04-2024 03:22, dxf wrote:
    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me. That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic. IMO it were better that RSHIFT/LSHIFT should fail than
    do this.

    For those interested in the entire fixed routine, here it is:

    : dlshift
    dup 0> 0= if drop ;then
    dup cell-bits - dup 0< 0= if >r drop drop r> lshift 0 swap ;then drop
    >r over 0 invert cell-bits r@ - dup >r lshift and r> rshift swap
    r@ lshift or swap r> lshift swap
    ;

    : drshift
    dup 0> 0= if drop ;then
    dup cell-bits - dup 0< 0= if >r drop nip r> rshift 0 ;then drop
    >r dup 0 invert cell-bits r@ - dup >r rshift and r> lshift swap
    r@ rshift spin r> rshift or swap
    ;

    : SPIN SWAP ROT ;
    : ;THEN POSTPONE EXIT POSTPONE THEN ; IMMEDIATE

    "cell-bits" should be obvious.

    Hans Bezemer
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Apr 8 21:14:29 2024
    From Newsgroup: comp.lang.forth

    On 7/04/2024 10:53 pm, Hans Bezemer wrote:
    On 01-04-2024 03:22, dxf wrote:
    While your double-shift algorithm produces the correct results (not shown here),
    the intermediate values presented to each RSHIFT/LSHIFT can be quite out-of-bounds
    e.g. a shift of 40 and -20 (actually FFFFFFE0) would concern me.  That an 'unambiguous'
    RSHIFT/LSHIFT will mask questionable parameters fed to it and return a result of 0,
    I for one find problematic.  IMO it were better that RSHIFT/LSHIFT should fail than
    do this.

    For those interested in the entire fixed routine, here it is:

    : dlshift
      dup 0> 0= if drop ;then
      dup cell-bits - dup 0< 0= if >r drop drop r> lshift 0 swap ;then drop
      >r over 0 invert cell-bits r@ - dup >r lshift and r> rshift swap
      r@ lshift or swap r> lshift swap
    ;

    : drshift
      dup 0> 0= if drop ;then
      dup cell-bits - dup 0< 0= if >r drop nip r> rshift 0 ;then drop
      >r dup 0 invert cell-bits r@ - dup >r rshift and r> lshift swap
      r@ rshift spin r> rshift or swap
    ;

    : SPIN SWAP ROT ;
    : ;THEN POSTPONE EXIT POSTPONE THEN ; IMMEDIATE

    "cell-bits" should be obvious.

    '8 cells' should work for most users.

    Here's a hack (fix?) of the routines from CForth: https://github.com/MitchBradley/cforth/blob/master/src/cforth/double.fth

    Seems to pass Krishna's tests (other than full double cell shift) but no warranty :)

    : DLSHIFT ( xd u -- xd2 )
    dup cell-bits u< not if nip cell-bits - lshift 0 swap exit then
    tuck lshift >r 2dup cell-bits swap - rshift r> or >r lshift r> ;

    : DRSHIFT ( xd u -- xd2 )
    dup cell-bits u< not if cell-bits - rshift nip 0 exit then
    2dup rshift >r tuck cell-bits swap - lshift -rot rshift or r> ;

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Tue Apr 9 13:53:53 2024
    From Newsgroup: comp.lang.forth

    On 8/04/2024 9:14 pm, dxf wrote:
    ...
    Here's a hack (fix?) of the routines from CForth: https://github.com/MitchBradley/cforth/blob/master/src/cforth/double.fth

    Seems to pass Krishna's tests (other than full double cell shift) but no warranty :)
    ...

    It appears the original also has a problem when shift is zero. A quick fix is:

    : DLSHIFT ( xd u -- xd2 )
    ?dup if
    dup cell-bits u< not if nip cell-bits - lshift 0 swap exit then
    tuck lshift >r 2dup cell-bits swap - rshift r> or >r lshift r>
    then ;
    : DRSHIFT ( xd u -- xd2 )
    ?dup if
    dup cell-bits u< not if cell-bits - rshift nip 0 exit then
    2dup rshift >r tuck cell-bits swap - lshift -rot rshift or r>
    then ;

    A test using random numbers and shifts suggests it now works. Reference definitions
    used were:

    : UD2/ ( xd1 -- xd2 ) d2/ [ 0 invert 1 rshift ] literal and ;
    : DRSHIFT2 ( xd1 n -- xd2 ) 0 ?do ud2/ loop ;
    : DLSHIFT2 ( xd1 n -- xd2 ) 0 ?do d2* loop ;

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Fri Apr 12 11:13:21 2024
    From Newsgroup: comp.lang.forth

    On 12/04/2024 1:11 am, albert@spenarnc.xs4all.nl wrote:

    While others indulge in endless discussions about DRSHIFT
    I thought to attempt some literate programming.

    It didn't prompt you to test your own implementation?

    ( D0= D0<> D0< D= D< D- M+ DRSHIFT DLSHIFT DU< ) \ AvdH B6Mar22

    : DLSHIFT >R SWAP DUP R@ LSHIFT SWAP 8 CELLS R@ - RSHIFT ROT R>
    LSHIFT OR ;

    : DRSHIFT >R DUP R@ RSHIFT SWAP 8 CELLS R@ - LSHIFT ROT R>
    RSHIFT OR SWAP ;

    0 4 d. 17179869184 ok
    0 4 0 drshift d. 17179869188 ok

    4 0 d. 4 ok
    4 0 0 dlshift d. 17179869188 ok

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Fri Apr 12 10:27:49 2024
    From Newsgroup: comp.lang.forth

    In article <66188ab1$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2024 1:11 am, albert@spenarnc.xs4all.nl wrote:

    While others indulge in endless discussions about DRSHIFT
    I thought to attempt some literate programming.

    It didn't prompt you to test your own implementation?

    ( D0= D0<> D0< D= D< D- M+ DRSHIFT DLSHIFT DU< ) \ AvdH B6Mar22

    : DLSHIFT >R SWAP DUP R@ LSHIFT SWAP 8 CELLS R@ - RSHIFT ROT R>
    LSHIFT OR ;

    : DRSHIFT >R DUP R@ RSHIFT SWAP 8 CELLS R@ - LSHIFT ROT R>
    RSHIFT OR SWAP ;

    0 4 d. 17179869184 ok
    0 4 0 drshift d. 17179869188 ok

    4 0 d. 4 ok
    4 0 0 dlshift d. 17179869188 ok


    Good catch! Shifting over 8 CELLS is an ambiguous condition.
    insert
    DUP 0= IF EXIT THEN
    in front of the code.
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat purring. - the Wise from Antrim -
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Apr 13 19:42:00 2024
    From Newsgroup: comp.lang.forth

    On 12/04/2024 6:27 pm, albert@spenarnc.xs4all.nl wrote:
    In article <66188ab1$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2024 1:11 am, albert@spenarnc.xs4all.nl wrote:

    While others indulge in endless discussions about DRSHIFT
    I thought to attempt some literate programming.

    It didn't prompt you to test your own implementation?

    ( D0= D0<> D0< D= D< D- M+ DRSHIFT DLSHIFT DU< ) \ AvdH B6Mar22

    : DLSHIFT >R SWAP DUP R@ LSHIFT SWAP 8 CELLS R@ - RSHIFT ROT R>
    LSHIFT OR ;

    : DRSHIFT >R DUP R@ RSHIFT SWAP 8 CELLS R@ - LSHIFT ROT R>
    RSHIFT OR SWAP ;

    0 4 d. 17179869184 ok
    0 4 0 drshift d. 17179869188 ok

    4 0 d. 4 ok
    4 0 0 dlshift d. 17179869188 ok


    Good catch! Shifting over 8 CELLS is an ambiguous condition.
    insert
    DUP 0= IF EXIT THEN
    in front of the code.

    That handles the specific case '0 shift' but the ambiguous condition
    you mention arises again here:

    HEX
    03 01 8 cells dlshift .( Expected: 00 03 Got: ) swap u. u. cr
    FF 00 8 cells dlshift .( Expected: 00 FF Got: ) swap u. u. cr
    00 01 8 cells drshift .( Expected: 01 00 Got: ) swap u. u. cr
    00 FF 8 cells drshift .( Expected: FF 00 Got: ) swap u. u. cr
    DECIMAL
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From mhx@mhx@iae.nl (mhx) to comp.lang.forth on Sat Apr 13 13:54:54 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni wrote:
    [..]
    Just tested DLSHIFT and found weird things going on. Traced the problem
    to LSHIFT.
    [..]
    1 64 LSHIFT . \ expected to get zero
    1 \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Interesting. Apparently this was changed somewhere in
    the course of time, as my local version of the spec. says:

    LSHIFT CORE
    ( u1 u -- u2 )
    Perform a logical shift of u bit-places on u1, giving u2. Shift the bits
    n places toward the most significant bit. Put zero into the places
    "uncovered" by the shift. When u is greater than or equal to the number
    of bits in a cell, u2 wraps around.

    Fortunately, this is exactly what AMD/Intel hardware does, and leads to

    FORTH> 1 64 lshift . 1 ok

    -marcel
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Sat Apr 13 18:29:42 2024
    From Newsgroup: comp.lang.forth

    On 4/13/24 08:54, mhx wrote:
    Krishna Myneni wrote:
    [..]
    Just tested DLSHIFT and found weird things going on. Traced the
    problem to LSHIFT.
    [..]
    1 64 LSHIFT .  \ expected to get zero
    1              \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an
    ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put
    zeroes into the least significant bits vacated by the shift. An
    ambiguous condition exists if u is greater than or equal to the number
    of bits in a cell.

    Interesting. Apparently this was changed somewhere in
    the course of time, as my local version of the spec. says:

    LSHIFT                                                                 CORE
        ( u1 u -- u2 )
        Perform a logical shift of u bit-places on u1, giving u2. Shift the bits
        n places toward the most significant bit. Put zero into the places
        "uncovered" by the shift. When u is greater than or equal to the number
        of bits in a cell, u2 wraps around.

    Fortunately, this is exactly what AMD/Intel hardware does, and leads to

    FORTH> 1 64 lshift . 1  ok

    -marcel

    The spec for LSHIFT which I posted is the same as the one in Forth-94
    (ANS Forth), so yours must have come from an earlier standard, or it
    just mirrors the SHL instruction spec for x86/x86_64. IMO the language
    spec shouldn't be tied to the behavior of a processor machine level instruction on a specific processor family.

    Also, I don't see what good a wrap-around shift is when u is greater
    than or equal to the bits in a cell. In what algorithm would you use
    such an operation? Bit operations such as a linear shift register where
    the bits drop off in the direction of the shift, or a bit rotation
    within a cell with an arbitrary number seem to be more useful.

    --
    Krishna



    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Apr 14 15:02:13 2024
    From Newsgroup: comp.lang.forth

    On 13/04/2024 11:54 pm, mhx wrote:
    Krishna Myneni wrote:
    [..]
    Just tested DLSHIFT and found weird things going on. Traced the problem to LSHIFT.
    [..]
    1 64 LSHIFT .  \ expected to get zero
    1              \ instead, got 1

    Then, I looked at the spec. for LSHIFT and, indeed, there is an ambiguous condition for u >= BITS_PER_CELL .


    6.1.1805
    LSHIFT “l-shift”
    CORE
    ( x1 u – – x2 )
    Perform a logical left shift of u bit-places on x1, giving x2. Put zeroes into the least significant bits vacated by the shift. An ambiguous condition exists if u is greater than or equal to the number of bits in a cell.

    Interesting. Apparently this was changed somewhere in
    the course of time, as my local version of the spec. says:

    LSHIFT                                                                 CORE
        ( u1 u -- u2 )
        Perform a logical shift of u bit-places on u1, giving u2. Shift the bits
        n places toward the most significant bit. Put zero into the places     "uncovered" by the shift. When u is greater than or equal to the number
        of bits in a cell, u2 wraps around.

    Fortunately, this is exactly what AMD/Intel hardware does, and leads to

    FORTH> 1 64 lshift . 1  ok

    Unfortunate for the Intel 8086 and folks who expected a 0 result.



    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sun Apr 14 13:06:12 2024
    From Newsgroup: comp.lang.forth

    In article <661a5369$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2024 6:27 pm, albert@spenarnc.xs4all.nl wrote:
    In article <66188ab1$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2024 1:11 am, albert@spenarnc.xs4all.nl wrote:

    While others indulge in endless discussions about DRSHIFT
    I thought to attempt some literate programming.

    It didn't prompt you to test your own implementation?

    ( D0= D0<> D0< D= D< D- M+ DRSHIFT DLSHIFT DU< ) \ AvdH B6Mar22

    : DLSHIFT >R SWAP DUP R@ LSHIFT SWAP 8 CELLS R@ - RSHIFT ROT R>
    LSHIFT OR ;

    : DRSHIFT >R DUP R@ RSHIFT SWAP 8 CELLS R@ - LSHIFT ROT R>
    RSHIFT OR SWAP ;

    0 4 d. 17179869184 ok
    0 4 0 drshift d. 17179869188 ok

    4 0 d. 4 ok
    4 0 0 dlshift d. 17179869188 ok


    Good catch! Shifting over 8 CELLS is an ambiguous condition.
    insert
    DUP 0= IF EXIT THEN
    in front of the code.

    That handles the specific case '0 shift' but the ambiguous condition
    you mention arises again here:

    HEX
    03 01 8 cells dlshift .( Expected: 00 03 Got: ) swap u. u. cr
    FF 00 8 cells dlshift .( Expected: 00 FF Got: ) swap u. u. cr
    00 01 8 cells drshift .( Expected: 01 00 Got: ) swap u. u. cr
    00 FF 8 cells drshift .( Expected: FF 00 Got: ) swap u. u. cr
    DECIMAL

    You are right. Totally annoyed with this. Changed the library to

    : DLSHIFT 0 ?DO 2DUP D+ LOOP ;

    : DRSHIFT 0 ?DO 2 UDM/MOD ROT DROP LOOP ;


    Groetjes Albert
    --
    Don't praise the day before the evening. One swallow doesn't make spring.
    You must not say "hey" before you have crossed the bridge. Don't sell the
    hide of the bear until you shot it. Better one bird in the hand than ten in
    the air. First gain is a cat purring. - the Wise from Antrim -
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Sun Apr 21 16:11:24 2024
    From Newsgroup: comp.lang.forth

    On 14-04-2024 13:06, albert@spenarnc.xs4all.nl wrote:
    In article <661a5369$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote:
    On 12/04/2024 6:27 pm, albert@spenarnc.xs4all.nl wrote:
    In article <66188ab1$1@news.ausics.net>, dxf <dxforth@gmail.com> wrote: >>>> On 12/04/2024 1:11 am, albert@spenarnc.xs4all.nl wrote:

    While others indulge in endless discussions about DRSHIFT
    I thought to attempt some literate programming.

    It didn't prompt you to test your own implementation?

    ( D0= D0<> D0< D= D< D- M+ DRSHIFT DLSHIFT DU< ) \ AvdH B6Mar22

    : DLSHIFT >R SWAP DUP R@ LSHIFT SWAP 8 CELLS R@ - RSHIFT ROT R>
    LSHIFT OR ;

    : DRSHIFT >R DUP R@ RSHIFT SWAP 8 CELLS R@ - LSHIFT ROT R>
    RSHIFT OR SWAP ;

    0 4 d. 17179869184 ok
    0 4 0 drshift d. 17179869188 ok

    4 0 d. 4 ok
    4 0 0 dlshift d. 17179869188 ok


    Good catch! Shifting over 8 CELLS is an ambiguous condition.
    insert
    DUP 0= IF EXIT THEN
    in front of the code.

    That handles the specific case '0 shift' but the ambiguous condition
    you mention arises again here:

    HEX
    03 01 8 cells dlshift .( Expected: 00 03 Got: ) swap u. u. cr
    FF 00 8 cells dlshift .( Expected: 00 FF Got: ) swap u. u. cr
    00 01 8 cells drshift .( Expected: 01 00 Got: ) swap u. u. cr
    00 FF 8 cells drshift .( Expected: FF 00 Got: ) swap u. u. cr
    DECIMAL

    Sure, I had to adapt it a bit: 4tH is segmented, so 1 CELLS renders 1.
    [HEX] only works at compile time, so HEX is added to allow for runtime behavior. And sure, not all of this stuff is core, so some libs are
    added as well.

    include lib/dbldot.4th \ if you insist..
    include lib/dshift.4th \ identical to routine posted on c.l.f.

    [HEX] HEX
    03 01 8 /cell * dlshift .( Expected: 00 03 Got: ) swap u. u. cr
    FF 00 8 /cell * dlshift .( Expected: 00 FF Got: ) swap u. u. cr
    00 01 8 /cell * drshift .( Expected: 01 00 Got: ) swap u. u. cr
    00 FF 8 /cell * drshift .( Expected: FF 00 Got: ) swap u. u. cr
    [DECIMAL] DECIMAL

    But it's rock solid:

    $ pp4th -x clfdrshift.4th
    Expected: 00 03 Got: 0 3
    Expected: 00 FF Got: 0 FF
    Expected: 01 00 Got: 1 0
    Expected: FF 00 Got: FF 0

    Hans Bezemer


    --- Synchronet 3.20a-Linux NewsLink 1.114