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).
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 <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.
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?
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.
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.
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.
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".
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.
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 ;
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.
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.
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/
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.
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.
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 916 |
Nodes: | 10 (1 / 9) |
Uptime: | 50:21:00 |
Calls: | 12,172 |
Calls today: | 2 |
Files: | 186,522 |
Messages: | 2,234,726 |