• D! and D@

    From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Fri Mar 22 08:59:24 2024
    From Newsgroup: comp.lang.forth

    For typical implementations of 2! and 2@, the storage of double length
    numbers in memory do not correspond to the native byte ordering for a
    double length number. For these implementations, the high order bits of
    the double number are on the top cell of the stack, which is at a lower
    memory address. For example,

    2variable x

    5 s>d .s

    0
    5
    ok

    x 2!

    x 8 dump \ on a 32-bit little-endian system

    A0AE7C0 : 00 00 00 00 05 00 00 00 ok

    In the Forth 2012 standard, and in prior standards, the representation
    of double numbers on the stack seems to be allowed to be implementation defined. Thus, on a 32-bit system, the stack order of a 64 bit double
    number, the standard does not specify whether the high 32 bits of the
    number are on top of the stack or the low 32 bits. Hence, we have the rationale (A.8.6.1.1140) for the word D>S to abstract the conversion of
    a double to single length number (instead of using DROP).

    To overcome this issue, we could simply decide that double length
    numbers on the stack have a specific ordering corresponding to their
    native memory ordering on the system, but this appears to be contrary to
    some existing implementations, and it may also break code.

    A better way to do this is to explicitly define D! and D@, so that the
    native memory storage order is consistent for this type.

    For little-endian Forth systems which place the high order cell of the
    double number on top of the stack, the definitions would be

    : D! ( d a -- ) >r swap r> 2! ;
    : D@ ( a -- d ) 2@ swap ;

    === Example ===
    5 s>d x d!
    ok
    x 8 dump

    A0AE7C0 : 05 00 00 00 00 00 00 00 ok

    x d@ .s
    0
    5
    ok
    === End Example ===

    More generally, the problem with the double number word set is that it attempts to use the same word set for two different types:

    1) pairs of cell length numbers
    2) double length integers

    It would be better to separate the words for these two types, the latter having prefix of "D" and the former having prefix "2".

    --
    Krishna Myneni

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Fri Mar 22 14:32:12 2024
    From Newsgroup: comp.lang.forth

    +1

    I did this long ago when CPU endianness "violated the Forth standard".

    That's also why my stack grows upwards and not downwards on system with
    Intel CPUs: double number arithmetic is performed in stack memory, without popping nybble or byte chunks off for reassembly, and pushing results back
    in the "right" order.
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Fri Mar 22 17:08:43 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    In the Forth 2012 standard, and in prior standards, the representation
    of double numbers on the stack seems to be allowed to be implementation >defined.

    No, the standard defines it:

    |3.1.4.1 Double-cell integers
    |
    |On the stack, the cell containing the most significant part of a
    |double-cell integer shall be above the cell containing the least
    |significant part.

    Thus, on a 32-bit system, the stack order of a 64 bit double
    number, the standard does not specify whether the high 32 bits of the
    number are on top of the stack or the low 32 bits.

    But it does.

    Hence, we have the
    rationale (A.8.6.1.1140) for the word D>S to abstract the conversion of
    a double to single length number (instead of using DROP).

    Have your read the rationale? It says:

    |There exist number representations, e.g., the sign-magnitude
    |representation, where reduction from double- to single-precision
    |cannot simply be done with DROP. This word, equivalent to DROP on
    |two's complement systems, desensitizes application code to number |representation and facilitates portability.

    So, the rationale says that, if you use the two's-complement
    representation of negative numbers (as you do), D>S is equivalent to
    DROP.

    More generally, the problem with the double number word set is that it >attempts to use the same word set for two different types:

    1) pairs of cell length numbers
    2) double length integers

    Standard Forth has the 2... words that work for any pairs of cells,
    whether they represent double numbers or something else. The
    double-number wordset includes some of these words. Standard Forth
    also has D... words for dealing with double-cell numbers. All these
    words are in the DOUBLE or DOUBLE EXT wordset.

    It would be better to separate the words for these two types, the latter >having prefix of "D" and the former having prefix "2".

    So what would you do with the 2... words that are in the DOUBLE or
    DOUBLE EXT wordset?

    I don't think that moving words between wordsets has benefits that
    exceed the costs.

    - 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 Fri Mar 22 15:13:28 2024
    From Newsgroup: comp.lang.forth

    On 3/22/24 12:08, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    In the Forth 2012 standard, and in prior standards, the representation
    of double numbers on the stack seems to be allowed to be implementation
    defined.

    No, the standard defines it:

    |3.1.4.1 Double-cell integers
    |
    |On the stack, the cell containing the most significant part of a |double-cell integer shall be above the cell containing the least |significant part.


    Ok. I did not look in the earlier part of the standard, only the section dealing with the double number word set.

    Thus, on a 32-bit system, the stack order of a 64 bit double
    number, the standard does not specify whether the high 32 bits of the
    number are on top of the stack or the low 32 bits.

    But it does.

    ...


    More generally, the problem with the double number word set is that it
    attempts to use the same word set for two different types:

    1) pairs of cell length numbers
    2) double length integers

    Standard Forth has the 2... words that work for any pairs of cells,
    whether they represent double numbers or something else. The
    double-number wordset includes some of these words. Standard Forth
    also has D... words for dealing with double-cell numbers. All these
    words are in the DOUBLE or DOUBLE EXT wordset.


    Yes, 2! and 2@ words work, but as I've pointed out, the storage for
    double length numbers isn't consistent with the expected native storage
    on a little endian system in which the stack grows towards lower
    addresses. The 2! and 2@ words are better suited for dealing with pairs
    of cell length numbers.

    It would be better to separate the words for these two types, the latter
    having prefix of "D" and the former having prefix "2".

    So what would you do with the 2... words that are in the DOUBLE or
    DOUBLE EXT wordset?


    I would place the 2... words into the Core Extensions word set.


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Mar 23 11:35:15 2024
    From Newsgroup: comp.lang.forth

    On 23/03/2024 7:13 am, Krishna Myneni wrote:
    On 3/22/24 12:08, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:

    More generally, the problem with the double number word set is that it
    attempts to use the same word set for two different types:

    1) pairs of cell length numbers
    2) double length integers

    Standard Forth has the 2... words that work for any pairs of cells,
    whether they represent double numbers or something else.  The
    double-number wordset includes some of these words.  Standard Forth
    also has D... words for dealing with double-cell numbers.  All these
    words are in the DOUBLE or DOUBLE EXT wordset.


    Yes, 2! and 2@ words work, but as I've pointed out, the storage for double length numbers isn't consistent with the expected native storage on a little endian system in which the stack grows towards lower addresses. The 2! and 2@ words are better suited for dealing with pairs of cell length numbers.

    An implementation could have D@ D! but it doesn't gain much and use is restricted to fetching/storing. Anything involving mixed math will need
    2@ 2! as it guarantees high-cell on top. When I've needed endianness, perversely it was 'big endian'.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Mar 23 06:28:36 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    Yes, 2! and 2@ words work, but as I've pointed out, the storage for
    double length numbers isn't consistent with the expected native storage
    on a little endian system in which the stack grows towards lower
    addresses.

    Let's see:

    |6.1.0310 2! ( x1 x2 a-addr -- )
    |
    |Store the cell pair x1 x2 at a-addr, with x2 at a-addr and x1 at the
    |next consecutive cell.

    If an in-memory stack grows towards lower addresses, x2 is at the
    lower address on the stack and also in memory, whereas x1 is at the
    higher address on the stack and also in memory. So there is
    consistency in this order.

    The order corresponds to cell-wise big-endian, which is not consistent
    with the byte-wise little-endian order that has won in the byte order
    wars. However, I have not experienced problems from this lack of
    consistency.

    As for DUMP, there are people who argue for big-endian because the
    byte dumps are more in line with the way we write arabic numbers in
    our left-to-write script (the arabs have a right-to-left script but
    also have the most significant digit leftmost). An option is to have
    cell dumps, and then the big-endian cell order for doubles has a
    consistent left-to-right digit order for both doubles and cells.

    With byte dumps of little-endian cell data, there is also the
    inconsistency of having each byte left-to-right and each cell bytewise right-to-left. Not a real problem, but if you want consistency ...

    - 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 minforth@minforth@gmx.net (minforth) to comp.lang.forth on Sat Mar 23 08:31:04 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni wrote:

    Yes, 2! and 2@ words work, but as I've pointed out, the storage for
    double length numbers isn't consistent with the expected native storage
    on a little endian system in which the stack grows towards lower
    addresses. The 2! and 2@ words are better suited for dealing with pairs
    of cell length numbers.

    I stumbled over another issue: when working with external libraries you
    can't pass (unsigned) long long arguments/results without pre/post processing. --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Mar 23 17:44:59 2024
    From Newsgroup: comp.lang.forth

    minforth@gmx.net (minforth) writes:
    I stumbled over another issue: when working with external libraries you
    can't pass (unsigned) long long arguments/results without pre/post processing.

    For direct arguments for calling C functions, there are lots of other
    pitfalls. In particular, in general, you don't know the actual type
    of the C argument: It can be, say, long on one platform and long long
    on another. And C long long tends to be 64 bits whether Forth
    double-cells are 64 bits or 128 bits.

    So Gforth's C interface lets you specify the Forth types for calling a
    C function; the C types are taken from the C declaraction (typically
    in a .h file), and the interface converts between the two.

    Another issue is C struct fields. Again, the actual C type of the
    field may differ between platforms, and the correspondence between the
    Forth and C types may also differ between platforms. I think that the
    proper solution for that problem is value-flavoured fields, but at
    least for now the Gforth C interface does not include this AFAIK.

    In any case, if you want to access a 64-bit value in native byte order
    on a system that may be a 32-bit system, Gforth (development) has:

    |xd@ ( c-addr – ud ) gforth-1.0 “x-d-fetch”
    |
    |ud is the zero-extended 64-bit value stored at c_addr.
    |
    |xd! ( ud c-addr – ) gforth-1.0 “x-d-store”
    |
    |Store the bottom 64 bits of ud at c_addr.

    This seems to be the kind of words you are looking for.

    Interestingly, when we discussed memory-access words in the Forth200x
    meeting last September, I presented the Gforth solution <https://gforth.org/manual/Special-Memory-Accesses.html>, and was
    given the task to make a proposal, based on these words, except that
    the committee did not want to have the XD... words in the proposal.

    - 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 Sat Mar 23 14:13:34 2024
    From Newsgroup: comp.lang.forth

    On 3/22/24 08:59, Krishna Myneni wrote:
    ...
    For little-endian Forth systems which place the high order cell of the double number on top of the stack, the definitions would be

    : D! ( d a -- ) >r swap r> 2! ;
    : D@ ( a -- d ) 2@ swap ;

    ...

    More generally, the problem with the double number word set is that it attempts to use the same word set for two different types:

    1) pairs of cell length numbers
    2) double length integers

    It would be better to separate the words for these two types, the latter having prefix of "D" and the former having prefix "2".


    On a possibly related note, standard Forth has D2* and D2/ but not
    DLSHIFT and DRSHIFT. These are double number, non-arithmetic, left shift
    and right shift words with a specified number of bits to shift.

    D2* is the same as 1 DLSHIFT

    but

    D2/ is the same as 1 DRSHIFT only for positive double numbers

    I had need for DLSHIFT and DRSHIFT recently, and this is what I came up
    with.

    \ u is the number of bits to shift
    1 cells 8 * constant BITS_PER_CELL
    0 value ubits

    : DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
    dup 0= IF drop EXIT THEN
    BITS_PER_CELL min to ubits
    ubits lshift swap
    dup >r ubits msbits or
    r> ubits lshift swap ;

    : DRSHIFT ( ud u -- ud2 )
    dup 0= IF drop EXIT THEN
    BITS_PER_CELL min to ubits
    swap ubits rshift
    swap dup >r ubits lsbits or
    r> ubits rshift ;

    With x86, it should be possible to write efficient versions of DLSHIFT
    and DRSHIFT using SHLD and SHRD instructions.

    --
    Krishna Myneni

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Krishna Myneni@krishna.myneni@ccreweb.org to comp.lang.forth on Sat Mar 23 14:16:18 2024
    From Newsgroup: comp.lang.forth

    On 3/23/24 14:13, Krishna Myneni wrote:
    ...
    I had need for DLSHIFT and DRSHIFT recently, and this is what I came up with.

    \ u is the number of bits to shift
    1 cells 8 * constant BITS_PER_CELL
    0 value ubits

    : DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
        dup 0= IF drop EXIT THEN
        BITS_PER_CELL min to ubits
        ubits lshift swap
        dup >r ubits msbits or
        r> ubits lshift swap ;

    : DRSHIFT ( ud u -- ud2 )
        dup 0= IF drop EXIT THEN
        BITS_PER_CELL min to ubits
        swap ubits rshift
        swap dup >r ubits lsbits or
        r> ubits rshift ;

    With x86, it should be possible to write efficient versions of DLSHIFT
    and DRSHIFT using SHLD and SHRD instructions.


    I left out the definitions of MSBITS and LSBITS (shown below):

    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 ;

    --
    KM


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

    On 3/23/24 14:16, Krishna Myneni wrote:
    On 3/23/24 14:13, Krishna Myneni wrote:
    ...
    I had need for DLSHIFT and DRSHIFT recently, and this is what I came
    up with.

    \ u is the number of bits to shift
    1 cells 8 * constant BITS_PER_CELL
    0 value ubits

    : DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
         dup 0= IF drop EXIT THEN
         BITS_PER_CELL min to ubits
         ubits lshift swap
         dup >r ubits msbits or
         r> ubits lshift swap ;

    : DRSHIFT ( ud u -- ud2 )
         dup 0= IF drop EXIT THEN
         BITS_PER_CELL min to ubits
         swap ubits rshift
         swap dup >r ubits lsbits or
         r> ubits rshift ;

    With x86, it should be possible to write efficient versions of DLSHIFT
    and DRSHIFT using SHLD and SHRD instructions.


    I left out the definitions of MSBITS and LSBITS (shown below):

     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 ;


    Just realized that these versions of DRSHIFT and DLSHIFT are limited to
    shift of 0 bits -- 1 cell width in bits, rather than the general shift
    count of 0 bits -- 2 cells width in bits. They have to be modified for
    general use on double length numbers. Of course one can write the
    general shifts in terms of these by applying them twice if needed.

    --
    Krishna


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Mar 24 13:18:38 2024
    From Newsgroup: comp.lang.forth

    On 24/03/2024 12:47 pm, Krishna Myneni wrote:
    On 3/23/24 14:16, Krishna Myneni wrote:
    On 3/23/24 14:13, Krishna Myneni wrote:
    ...
    I had need for DLSHIFT and DRSHIFT recently, and this is what I came up with.

    \ u is the number of bits to shift
    1 cells 8 * constant BITS_PER_CELL
    0 value ubits

    : DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
         dup 0= IF drop EXIT THEN
         BITS_PER_CELL min to ubits
         ubits lshift swap
         dup >r ubits msbits or
         r> ubits lshift swap ;

    : DRSHIFT ( ud u -- ud2 )
         dup 0= IF drop EXIT THEN
         BITS_PER_CELL min to ubits
         swap ubits rshift
         swap dup >r ubits lsbits or
         r> ubits rshift ;

    With x86, it should be possible to write efficient versions of DLSHIFT and DRSHIFT using SHLD and SHRD instructions.


    I left out the definitions of MSBITS and LSBITS (shown below):

      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 ;


    Just realized that these versions of DRSHIFT and DLSHIFT are limited to shift of 0 bits -- 1 cell width in bits, rather than the general shift count of 0 bits -- 2 cells width in bits. They have to be modified for general use on double length numbers. Of course one can write the general shifts in terms of these by applying them twice if needed.

    Indeed. I was expecting:

    : DLSHIFT ( ud u -- ud2 ) 0 ?DO D2* LOOP ;

    DRSHIFT would require DU2/

    Similarly missing from Standards was U2/ (the basis of RSHIFT).

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sun Mar 24 07:37:40 2024
    From Newsgroup: comp.lang.forth

    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On a possibly related note, standard Forth has D2* and D2/ but not
    DLSHIFT and DRSHIFT. These are double number, non-arithmetic, left shift
    and right shift words with a specified number of bits to shift.

    Gforth has DLSHIFT, DRSHIFT, and DARSHIFT (the latter works on signed
    doubles). They are used exactly 0 times in the Gforth image. There
    are uses in the cross-compiler (for building 64-bit images on 32-bit
    machines) and in MINOS2.

    - 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 mhx@mhx@iae.nl (mhx) to comp.lang.forth on Sun Mar 24 09:16:10 2024
    From Newsgroup: comp.lang.forth

    Anton Ertl wrote:

    Gforth has DLSHIFT, DRSHIFT, and DARSHIFT (the latter works on signed doubles). They are used exactly 0 times in the Gforth image. There
    are uses in the cross-compiler (for building 64-bit images on 32-bit machines) and in MINOS2.

    I appear not to have an equivalent for DARSHIFT (maybe coded in
    high-level somewhere), but the other two appear in my examples (some
    13,225 files in total) :

    Searching for: DLSHIFT
    D:\dfwforth\examples\bignum\lperfect.frt(351): : d2^x ( n -- d ) 1. ROT D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(598): 1. BLOECKE DLSHIFT D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(599): 1. BLOECKE #32 - DLSHIF D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(638): :NONAME #64 0 ?DO 1. I D:\dfwforth\examples\digsound\3drums.frt(181): x TLoupe DLSHIFT Xmax 2* D:\dfwforth\examples\euler\euler162.frt(56): : SOLUTIONS ( -- ud ) 0. #1 D:\dfwforth\examples\euler\euler22.frt(69): #12 MIN DUP >R 0 ?DO C@+ 1+ D:\dfwforth\examples\euler\euler22.frt(70): hash #12 R> - 5 * DLSHIFT n D:\dfwforth\examples\fermat\perfect2.frt(89): : d2^x ( n -- d ) 1. ROT D:\dfwforth\examples\graphics\turtle.frt(314): step U>D #19 DLSHIFT ( 0 D:\dfwforth\examples\misc\lzwpack.frt(106): /bits 8 - DLSHIFT SWAP D:\dfwforth\examples\misc\lzwpack.frt(126): /bits 8 DO 8 DLSHIFT SWAP D:\dfwforth\examples\misc\mullen4.frt(102): >R 3 DLSHIFT D:\dfwforth\examples\misc\mullen4.frt(113): 3 DLSHIFT D:\dfwforth\examples\misc\pentoalbert.frt(109): \ : DLSHIFT >R SWAP DU D:\dfwforth\examples\mix\compat.frt(83): : DLSHIFT ( d1 n -- d2 n ) D:\dfwforth\examples\mix\compat.frt(84): ABORT" DLSHIFT : make your home D:\dfwforth\examples\mix\mix.frt(810): U>D [ /bytes /bits * ] LITERAL DL D:\dfwforth\examples\mix\mix.frt(938): CALC-ADDR ABS 11 MOD /bits * DLSH D:\dfwforth\examples\mix\mix.frt(951): 2SWAP S> DLSHIFT DOR USPLIT10 D:\dfwforth\examples\mix\mix.frt(956): 2DUP [ 10 /bits * ] LITERAL S - D D:\dfwforth\examples\mix\mix.frt(1874): U>D [ /bytes /bits * ] LITERAL D D:\dfwforth\examples\numeric\cubicsine.frt(58): : d4* 2 DLSHIFT ; D:\dfwforth\examples\numeric\cubicsine.frt(61): : d16* 4 DLSHIFT ; D:\dfwforth\examples\shoot-2001-06-05\bench\meteor\mmeteor.frt(186): 0. D:\dfwforth\examples\sod64\cross.frt(211): U>D OPSHIFT @ DLSHIFT D:\dfwforth\examples\sod64\cross.frt(225): "HEADER OVER C, 1 DLSHIFT D:\dfwforth\examples\sod64\longhand.frt(44): -- Use DLSHIFT32 with shift D:\dfwforth\examples\sod64\longhand.frt(48): QuotientLow 1 DLSHIFT32 D:\dfwforth\examples\sod64\longhand.frt(49): QuotientHigh 1 DLSHIFT32 SW D:\dfwforth\examples\sod64\longhand.frt(50): Remainder 1 DLSHIFT32 SW D:\dfwforth\examples\sod64\sod64.frt(242): : DO_LSHIFT 2POPR DROP DLSHI D:\dfwforth\examples\threads\pipid2.frt(23): \ : DLSHIFT 0 ?DO D2* LO D:\dfwforth\examples\threads\pipid2.frt(132): 3 DLSHIFT D:\dfwforth\examples\threads\pipidch.frt(223): : *10 ( d -- 10*d ) 2DUP D:\dfwforth\examples\threads\pipidchm.frt(225): : *10 ( d -- 10*d ) 2DUP D:\dfwforth\examples\threads\pipidn.frt(24): \ : DLSHIFT 0 ?DO D2* LO D:\dfwforth\examples\threads\pipidn.frt(147): : *10 ( d -- 10*d ) 2DUP D D:\dfwforth\include\bignum.frt(411): @- U>D places DLSHIFT carry U>D D D:\dfwforth\include\hexfloat.frt(74): [ELSE] : lshiftnum ( n -- ) the D:\dfwforth\include\hexfloat.frt(75): : dl1shift ( u32lo1 u32hi1 n -- u3 D:\dfwforth\include\hexfloat.frt(197): ELSE OVER C@ #16 DIGIT? IF U>D D:\dfwforth\include\hexfloat.frt(205): BEGIN #bits #want < WHILE 4 DLS D:\dfwforth\include\intfft.frt(73): re2 im1 M* re1 im2 M* D+ #SHIFTER D D:\dfwforth\include\intfft.frt(74): re1 re2 M* im1 im2 M* D- #SHIFTER D D:\dfwforth\include\intfft.frt(152): M* #SHIFTER DLSHIFT NIP D:\dfwforth\include\miscutil.frt(1090): : _int ( ud1 -- ud2 ) 2 DL D:\dfwforth\include\miscutil.frt(1091): : _sxint ( ud1 -- ud2 ) 2 DL D:\dfwforth\include\miscutil.frt(1092): : _double ( ud1 -- ud2 ) 2 DL D:\dfwforth\include\miscutil.frt(1093): : _float ( ud1 -- ud2 ) 2 DL D:\dfwforth\include\miscutil.frt(2001): >R 2 DLSHIFT R> D:\dfwforth\include\quads.frt(87): ss IF ss DLSHIFT D:\dfwforth\include\quads.frt(90): ss DLSHIFT low-dividend 2!
    Found 53 occurrence(s) in 26 file(s), 1252 ms

    Searching for: DRSHIFT
    D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(963): p BLOECKE #32 - DRSHIFT D:\dfwforth\examples\ctpuzzle\ctpuzzle.frt(989): p BLOECKE DRSHIFT DROP D:\dfwforth\examples\euler\euler22.frt(74): CR #12 0 DO name #11 I - 5 D:\dfwforth\examples\misc\floatemu.frt(45): 1 DRSHIFT ; D:\dfwforth\examples\misc\floatemu.frt(49): >R DUP 2@ R> DRSHIFT D:\dfwforth\examples\misc\lzwpack.frt(113): 8 DRSHIFT D:\dfwforth\examples\misc\lzwpack.frt(130): /bits 8 - DRSHIFT D:\dfwforth\examples\misc\mullen4.frt(77): 3 DRSHIFT R> ; D:\dfwforth\examples\misc\pentoalbert.frt(108): \ : DRSHIFT 2DUP RSHIF D:\dfwforth\examples\misc\pentoalbert.frt(212): WHILE SWAP HEIGHT DRSHI D:\dfwforth\examples\mix\compat.frt(86): : DRSHIFT ( d1 n -- d2 n ) D:\dfwforth\examples\mix\compat.frt(87): ABORT" DRSHIFT : make your home D:\dfwforth\examples\mix\mix.frt(926): [ /bytes /bits * ] LITERAL DRSHIF D:\dfwforth\examples\mix\mix.frt(942): CALC-ADDR ABS 11 MOD /bits * DRSH D:\dfwforth\examples\mix\mix.frt(950): 2DUP [ 10 /bits * ] LITERAL S - D D:\dfwforth\examples\mix\mix.frt(957): 2SWAP S> DRSHIFT DOR USPLIT10 D:\dfwforth\examples\sod64\cross.frt(243): OVER 1 AND 0= ABORT" Instruct D:\dfwforth\examples\sod64\cross.frt(256): 5 DRSHIFT D:\dfwforth\examples\sod64\sod64.frt(243): : DO_RSHIFT 2POPR DROP DRSHI D:\dfwforth\examples\sod64\sod64.frt(332): ir 1 DRSHIFT TO ir D:\dfwforth\examples\sod64\sod64.frt(335): ir 5 DRSHIFT TO ir D:\dfwforth\examples\sod64\sod64.frt(388): ir 1 DRSHIFT TO ir D:\dfwforth\examples\sod64\sod64.frt(392): ir 5 DRSHIFT TO ir D:\dfwforth\include\bignum.frt(433): @+ 0 SWAP places DRSHIFT 0 carry D:\dfwforth\include\hexfloat.frt(78): S> DRSHIFT R> U>D D+ ; PRIVATE D:\dfwforth\include\hexfloat.frt(81): S> DRSHIFT R> U>D D+ ; PRIVATE D:\dfwforth\include\hexfloat.frt(90): 1 OF #12 DRSHIFT # ENDOF D:\dfwforth\include\hexfloat.frt(91): 2 OF 8 DRSHIFT # # ENDOF D:\dfwforth\include\hexfloat.frt(92): 3 OF 4 DRSHIFT # # # ENDOF D:\dfwforth\include\miscutil.frt(1106): 2 DRSHIFT D:\dfwforth\include\miscutil.frt(1146): 2 DRSHIFT D:\dfwforth\include\miscutil.frt(1974): \ UM+ 1 DRSHIFT D:\dfwforth\include\miscutil.frt(2015): 2DUP 1 DRSHIFT DROP D:\dfwforth\include\miscutil.frt(2019): U+. 1 DRSHIFT DROP D:\dfwforth\include\quads.frt(52): : DU2/ 1 DRSHIFT ; D:\dfwforth\include\quads.frt(88): 2OVER cell-size 2* ss - DRSHIFT D+ D:\dfwforth\include\quads.frt(120): r0 2@ m 2@ D- ss DRSHIFT
    Found 37 occurrence(s) in 14 file(s), 7388 ms

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

    On 3/23/24 21:18, dxf wrote:
    On 24/03/2024 12:47 pm, Krishna Myneni wrote:
    On 3/23/24 14:16, Krishna Myneni wrote:
    On 3/23/24 14:13, Krishna Myneni wrote:
    ...
    I had need for DLSHIFT and DRSHIFT recently, and this is what I came up with.

    \ u is the number of bits to shift
    1 cells 8 * constant BITS_PER_CELL
    0 value ubits

    : DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
         dup 0= IF drop EXIT THEN
         BITS_PER_CELL min to ubits
         ubits lshift swap
         dup >r ubits msbits or
         r> ubits lshift swap ;

    : DRSHIFT ( ud u -- ud2 )
         dup 0= IF drop EXIT THEN
         BITS_PER_CELL min to ubits
         swap ubits rshift
         swap dup >r ubits lsbits or
         r> ubits rshift ;

    With x86, it should be possible to write efficient versions of DLSHIFT and DRSHIFT using SHLD and SHRD instructions.


    I left out the definitions of MSBITS and LSBITS (shown below):

      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 ;


    Just realized that these versions of DRSHIFT and DLSHIFT are limited to shift of 0 bits -- 1 cell width in bits, rather than the general shift count of 0 bits -- 2 cells width in bits. They have to be modified for general use on double length numbers. Of course one can write the general shifts in terms of these by applying them twice if needed.

    Indeed. I was expecting:

    : DLSHIFT ( ud u -- ud2 ) 0 ?DO D2* LOOP ;


    I had considered coding D2* with a loop using D2* but thought it would
    be faster to do it with LSHIFT and RSHIFT. In the end I will implement
    it as an intrinsic word in assembly, using the SHLD instruction.

    DRSHIFT would require DU2/


    Yes, but SHRD is more efficient, if it is available.

    --
    KM

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

    On 3/24/24 02:37, Anton Ertl wrote:
    Krishna Myneni <krishna.myneni@ccreweb.org> writes:
    On a possibly related note, standard Forth has D2* and D2/ but not
    DLSHIFT and DRSHIFT. These are double number, non-arithmetic, left shift
    and right shift words with a specified number of bits to shift.

    Gforth has DLSHIFT, DRSHIFT, and DARSHIFT (the latter works on signed doubles). They are used exactly 0 times in the Gforth image. There
    are uses in the cross-compiler (for building 64-bit images on 32-bit machines) and in MINOS2.


    I'm considering writing a portable IEEE 754-compatible quad-precision
    floating point arithmetic module in Forth, along the lines of the C++
    package QPFloat [1]. For a 64-bit Forth, DLSHIFT and DRSHIFT are useful primitives.

    --
    Krishna


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Mar 25 01:12:14 2024
    From Newsgroup: comp.lang.forth

    On 25/03/2024 12:04 am, Krishna Myneni wrote:
    On 3/23/24 21:18, dxf wrote:
    On 24/03/2024 12:47 pm, Krishna Myneni wrote:
    On 3/23/24 14:16, Krishna Myneni wrote:
    On 3/23/24 14:13, Krishna Myneni wrote:
    ...
    I had need for DLSHIFT and DRSHIFT recently, and this is what I came up with.

    \ u is the number of bits to shift
    1 cells 8 * constant BITS_PER_CELL
    0 value ubits

    : DLSHIFT ( ud u -- ud2 ) BITS_PER_CELL min 0 ?DO D2* LOOP ;
          dup 0= IF drop EXIT THEN
          BITS_PER_CELL min to ubits
          ubits lshift swap
          dup >r ubits msbits or
          r> ubits lshift swap ;

    : DRSHIFT ( ud u -- ud2 )
          dup 0= IF drop EXIT THEN
          BITS_PER_CELL min to ubits
          swap ubits rshift
          swap dup >r ubits lsbits or
          r> ubits rshift ;

    With x86, it should be possible to write efficient versions of DLSHIFT and DRSHIFT using SHLD and SHRD instructions.


    I left out the definitions of MSBITS and LSBITS (shown below):

       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 ;


    Just realized that these versions of DRSHIFT and DLSHIFT are limited to shift of 0 bits -- 1 cell width in bits, rather than the general shift count of 0 bits -- 2 cells width in bits. They have to be modified for general use on double length numbers. Of course one can write the general shifts in terms of these by applying them twice if needed.

    Indeed. I was expecting:

    : DLSHIFT ( ud u -- ud2 ) 0 ?DO D2* LOOP ;


    I had considered coding D2* with a loop using D2* but thought it would be faster to do it with LSHIFT and RSHIFT. In the end I will implement it as an intrinsic word in assembly, using the SHLD instruction.

    DRSHIFT would require DU2/


    Yes, but SHRD is more efficient, if it is available.

    Those are implementation details. Ideally one would have both words - one bit shift and
    multiple bit shift. To use 2* to shift one way, and 1 RSHIFT to shift the other seemed
    incongruous so I implemented U2/ . The latter also happened to be shorter/faster.

    --- Synchronet 3.20a-Linux NewsLink 1.114