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?
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 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:Of course one can write the general shifts in terms of these by applying them twice if needed.
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.
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.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 300 |
Nodes: | 16 (2 / 14) |
Uptime: | 46:32:36 |
Calls: | 6,710 |
Calls today: | 3 |
Files: | 12,243 |
Messages: | 5,354,355 |
Posted today: | 1 |