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.
Standard source definitions of DLSHIFT and DRSHIFT (double number left
shift and right shift), over full shift range, per discussion in prior thread.
...
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.
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 ===
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.
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.
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.
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.
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.
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 ===
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"
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.
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?
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.
These words should be in assembler anyway.
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.
=== "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.
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.
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.
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!Ideally — yes.
u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits. >>>
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.
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).
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!Ideally — yes.
u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits. >>>>
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.
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.
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!Ideally — yes.
u 64 LSHIFT should be zero on all systems with cell sizes up to 64 bits. >>>>>
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.
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.
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
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"
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
;
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.
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.
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.
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
...
And no idea what happens with less robust LSHIFT or RSHIFT implementations.
...
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
;
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.
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.
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
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).
On 30/03/2024 1:32 am, Hans Bezemer wrote:I see where you're going with this. I have two things to say about this:
...
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.
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.
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
The only viable alternative is:
: DLSHIFT ( xd1 n -- xd2) 0 ?do d2* loop ;
: DRSHIFT ( xd1 n -- xd2) 0 ?do d2/ loop ;
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?
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.
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
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.
...
LSHIFT/RSHIFT was intended to support the corresponding machine-code primitives available on
modern architectures.
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
That led to this Jan 1992 message:
https://groups.google.com/g/comp.lang.forth/c/DqrKMIiyLWc/m/1XUyYBaHyfYJ
The bidirectional shift operator is probably a result of the parsimony|
of Forth philosophy; why have two operators when one will do.
On 04-04-2024 09:42, dxf wrote:
On 2/04/2024 2:02 pm, dxf wrote:Fun part - 4tH still has SHIFT, performing exactly as indicated. LSHIFT is exactly like SHIFT, while RSHIFT is expanded to NEGATE SHIFT.
...
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
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
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.
...
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.
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.
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.
...
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 :)
...
While others indulge in endless discussions about DRSHIFT
I thought to attempt some literate programming.
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
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.
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.
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
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
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
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
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 915 |
Nodes: | 10 (2 / 8) |
Uptime: | 44:29:23 |
Calls: | 12,170 |
Files: | 186,521 |
Messages: | 2,234,564 |