Many forths define MU/MOD or equivalent:
: MU/MOD ( ud u -- urem udquot )
tuck 0 swap um/mod >r swap um/mod r> ;
Chances are if an app needs divide it will also need multiply.
With no logical
equivalent most use M*/ to do the multiply.
However it's a beast of a function.
Preferring something leaner I defined:
\ Multiply double by single leaving double.
: MU* ( ud1 u -- ud2 )
tuck * >r um* r> + ;
AFAIK MU* also works with signed inputs which is a bonus.
dxforth <dxforth@gmail.com> writes:
Many forths define MU/MOD or equivalent:
: MU/MOD ( ud u -- urem udquot )
tuck 0 swap um/mod >r swap um/mod r> ;
Chances are if an app needs divide it will also need multiply.
double/single->double division exists for one reason: to serve as
factor of #. E.g., in Gforth:
: # ( ud1 -- ud2 ) \ core number-sign
\G Used between @code{<<#} and @code{#>}. Prepend the
\G least-significant digit (according to @code{base}) of @var{ud1}
\G to the pictured numeric output string. @var{ud2} is
\G @var{ud1/base}, i.e., the number representing the remaining
\G digits.
\ special-casing base=#10 does not pay off:
\ <2022Mar11.130937@mips.complang.tuwien.ac.at>
base @ ud/mod rot dup 9 u>
[ char A char 9 1+ - ] Literal and +
'0' + hold ;
Unsurprisingly, >NUMBER needs a double-by-single->double
multiplication.
With no logical
equivalent most use M*/ to do the multiply.
I would find that surprising. Gforth uses a >NUMBER factor called ACCUMULATE:
: accumulate ( +d0 addr digit - +d1 addr )
swap >r swap base @ um* drop rot base @ um* d+ r> ;
SwiftForth puts the following line directly in >NUMBER:
SWAP >R 2SWAP BASE @ * SWAP BASE @ UM* D+ ROT 1+
So what makes you think that "most use M*/"?
However it's a beast of a function.
Preferring something leaner I defined:
\ Multiply double by single leaving double.
: MU* ( ud1 u -- ud2 )
tuck * >r um* r> + ;
AFAIK MU* also works with signed inputs which is a bonus.
Maybe it works with a signed double operand, but certainly not with a
signed single operand:
#-5. 3 mu* d. -15 ok
#5. -3 mu* d. 92233720368547758065 ok
#-5. -3 mu* d. -92233720368547758065 ok
dxforth <dxforth@gmail.com> writes:<SNIP>
AFAIK MU* also works with signed inputs which is a bonus.
Maybe it works with a signed double operand, but certainly not with a
signed single operand:
#-5. 3 mu* d. -15 ok
#5. -3 mu* d. 92233720368547758065 ok
#-5. -3 mu* d. -92233720368547758065 ok
- anton
\ Multiply double by single leaving double.
: MU* ( ud1 u -- ud2 )
tuck * >r um* r> + ;
AFAIK MU* also works with signed inputs which is a bonus. I never cared for the name MU/MOD but with the addition of companion function MU* I'm warming to it.
In article <2023Jul6.074556@mips.complang.tuwien.ac.at>,
Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
dxforth <dxforth@gmail.com> writes:<SNIP>
...: MU* ( ud1 u -- ud2 )
tuck * >r um* r> + ;
AFAIK MU* also works with signed inputs which is a bonus.
Maybe it works with a signed double operand, but certainly not with a >>signed single operand:
#-5. 3 mu* d. -15 ok
#5. -3 mu* d. 92233720368547758065 ok
#-5. -3 mu* d. -92233720368547758065 ok
Maybe it happens to work with *his* implementation/ Forth du jour.
This stresses the need for a specification of mu* and to check
each use against the specification.
On Thursday, July 6, 2023 at 6:10:55 AM UTC+2, dxforth wrote:
\ Multiply double by single leaving double.
: MU* ( ud1 u -- ud2 )
tuck * >r um* r> + ;
AFAIK MU* also works with signed inputs which is a bonus. I never cared for >> the name MU/MOD but with the addition of companion function MU* I'm warming >> to it.
As others have pointed out already, your MU* routine is for unsigned numbers. Your stack comment is correct.
I am using the following definitions for this kind of multiplication:
: UD* ( ud1 u -- ud2)
TUCK * >R UM* R> + ;
\ unsigned multiplication with truncated result
On 6/07/2023 7:55 pm, Heinrich Hohl wrote:
: UD* ( ud1 u -- ud2)Would like to see evidence signed multiplicand doesn't work before ruling it out.
TUCK * >R UM* R> + ;
\ unsigned multiplication with truncated result
200x has mandated 2's complement arithmetic. It would be amiss not to exploit it.
TUCK * >R UM* R> + ;
On Thursday, July 6, 2023 at 12:32:32 PM UTC+2, dxforth wrote:
On 6/07/2023 7:55 pm, Heinrich Hohl wrote:
Note that this is multiplication with a truncated result. This means that we may lose: UD* ( ud1 u -- ud2)Would like to see evidence signed multiplicand doesn't work before ruling it out.
TUCK * >R UM* R> + ;
\ unsigned multiplication with truncated result
200x has mandated 2's complement arithmetic. It would be amiss not to exploit it.
sign information of the input arguments partly or fully.
On Thursday, July 6, 2023 at 12:32:32 PM UTC+2, dxforth wrote:
On 6/07/2023 7:55 pm, Heinrich Hohl wrote:
: UD* ( ud1 u -- ud2)Would like to see evidence signed multiplicand doesn't work before ruling it out.
TUCK * >R UM* R> + ;
\ unsigned multiplication with truncated result
200x has mandated 2's complement arithmetic. It would be amiss not to exploit it.
Note that this is multiplication with a truncated result. This means that we may lose
sign information of the input arguments partly or fully.
The UD* routine works correctly with the full range of unsigned numbers.
Due to truncation and loss of sign information, it also happens to work with a limited range
of signed numbers. This means that the following stack comment is also correct:
: UD* ( d1 n+ -- d2)
TUCK * >R UM* R> + ;
In this case, d1 and d2 have full range, but n is limited to 0...$7FFF (in 16 bits),
i.e. it must be non-negative. It makes little sense to call such a routine "signed",
because not all arguments may use the full range of signed numbers.
I believe the correct stack comment is:
UD* ( d|ud1 u -- d|ud2)
I consider a routine 'signed' if any of the inputs in use are explicitly negative.
By your definition M*/ would not be signed.
On Friday, July 7, 2023 at 4:56:00 AM UTC+2, dxforth wrote:
I believe the correct stack comment is:
UD* ( d|ud1 u -- d|ud2)
No. Try a few examples, e.g.
3. 5 UD* UD. ---> 15, correct result
-3. 5 UD* D. ---> -15, correct result
but
3. -5 UD* gives wrong result, with UD. as well as with D.
-3. -5 UD* gives wrong result, with UD. as well as with D.
I consider a routine 'signed' if any of the inputs in use are explicitly negative.
By your definition M*/ would not be signed.
This is in the eye of the beholder. In my eyes M*/ is not a fully signed routine.
In M*/ ( d1 n1 +n2 -- d2), the divisor n2 must not be negative.
The Forth Standard allows this restriction because negative n2
does not seem to be required in typical applications.
I can live with that, although I would have preferred the requirement
( d1 n1 n2 -- d2) for reasons of consistency. Much easier to memorize.
My own rule for math operators is:
A leading "U" signals that all parameter (input and output) are unsigned
with full range of unsigned numbers.
It there is no leading "U", this signals that all parameters (input and output)
are signed with full range of signed numbers.
This is how I defined my own library of math operators, and the related
stack effects are very easy to memorize. I generally start with the unsigned operator. Then I define the related signed operator by calculating the overall
sign of the result first, then forming absolute values of the input parameters
and forwarding these to the unsigned routine. In the last step the overall sign
is applied to the unsigned result.
Examples: UD* ( ud1 u -- ud2 ) and D* ( d1 n -- d2) as shown in my fist post
of this thread.
On Friday, July 7, 2023 at 4:56:00 AM UTC+2, dxforth wrote:
I believe the correct stack comment is:
UD* ( d|ud1 u -- d|ud2)
No. Try a few examples, e.g.
3. 5 UD* UD. ---> 15, correct result
-3. 5 UD* D. ---> -15, correct result
but
3. -5 UD* gives wrong result, with UD. as well as with D.
-3. -5 UD* gives wrong result, with UD. as well as with D.
So the correct stack comments are
UD* (ud1 u -- ud2) or (d1 n+ -- d2)
Note that "n+" is not the same as "u"; n+ is the lower 50% of range
of an unsigned number.
I consider a routine 'signed' if any of the inputs in use areexplicitly negative.
By your definition M*/ would not be signed.
This is in the eye of the beholder. In my eyes M*/ is not a fully signed >routine.
In M*/ ( d1 n1 +n2 -- d2), the divisor n2 must not be negative.
The Forth Standard allows this restriction because negative n2
does not seem to be required in typical applications.
I can live with that, although I would have preferred the requirement
( d1 n1 n2 -- d2) for reasons of consistency. Much easier to memorize.
My own rule for math operators is:
A leading "U" signals that all parameter (input and output) are unsigned
with full range of unsigned numbers.
It there is no leading "U", this signals that all parameters (input and output)
are signed with full range of signed numbers.
This is how I defined my own library of math operators, and the related
stack effects are very easy to memorize. I generally start with the unsigned >operator. Then I define the related signed operator by calculating the overall >sign of the result first, then forming absolute values of the input parameters >and forwarding these to the unsigned routine. In the last step the overall sign
is applied to the unsigned result.
Examples: UD* ( ud1 u -- ud2 ) and D* ( d1 n -- d2) as shown in
my fist post
of this thread.
In article <ecafaa3e-d359-46b5...@googlegroups.com>,
Heinrich Hohl <hheinri...@gmail.com> wrote:
On Friday, July 7, 2023 at 4:56:00 AM UTC+2, dxforth wrote:
I believe the correct stack comment is:
UD* ( d|ud1 u -- d|ud2)
No. Try a few examples, e.g.
3. 5 UD* UD. ---> 15, correct result
-3. 5 UD* D. ---> -15, correct result
but
3. -5 UD* gives wrong result, with UD. as well as with D.
-3. -5 UD* gives wrong result, with UD. as well as with D.
So the correct stack comments are
UD* (ud1 u -- ud2) or (d1 n+ -- d2)
Note that "n+" is not the same as "u"; n+ is the lower 50% of range
of an unsigned number.
I consider a routine 'signed' if any of the inputs in use areexplicitly negative.
By your definition M*/ would not be signed.
This is in the eye of the beholder. In my eyes M*/ is not a fully signed >routine.
In M*/ ( d1 n1 +n2 -- d2), the divisor n2 must not be negative.
The Forth Standard allows this restriction because negative n2
does not seem to be required in typical applications.
I can live with that, although I would have preferred the requirement
( d1 n1 n2 -- d2) for reasons of consistency. Much easier to memorize.
My own rule for math operators is:
A leading "U" signals that all parameter (input and output) are unsigned >with full range of unsigned numbers.
It there is no leading "U", this signals that all parameters (input and output)
are signed with full range of signed numbers.
This is how I defined my own library of math operators, and the related >stack effects are very easy to memorize. I generally start with the unsigned
operator. Then I define the related signed operator by calculating the overall
sign of the result first, then forming absolute values of the input parameters
and forwarding these to the unsigned routine. In the last step the overall sign
is applied to the unsigned result.
Examples: UD* ( ud1 u -- ud2 ) and D* ( d1 n -- d2) as shown inMy take on this is as follows: defaults signed unless a prefix U.
my fist post
of this thread.
Prefix U then all operands all unsigned.
A prefix M means mixed mode
* single to double (what else)
/ double single (what else)
result to single single.
Inserting a D in front op de operator:
For multiplication this make only sense for inputs, one operand goes
to double.
For division this make only sense for outputs,
as this makes no sense for the remainder as the divisor is single.
It applies to the quotient,
So at last I can remember everything.
The FIGForth M/MOD has to be renamed to UDM/MOD .
I have no patience for mixing unsigned and signed.
This is a recipe for disaster. If it were to be applicable,
I'd define a separate word in the preamble of the program,
with a ton of comment.
In article <ecafaa3e-d359-46b5-8dc0-e996e44cbd3dn@googlegroups.com>,
Heinrich Hohl <hheinrich.hohl@gmail.com> wrote:
On Friday, July 7, 2023 at 4:56:00 AM UTC+2, dxforth wrote:
I believe the correct stack comment is:
UD* ( d|ud1 u -- d|ud2)
No. Try a few examples, e.g.
3. 5 UD* UD. ---> 15, correct result
-3. 5 UD* D. ---> -15, correct result
but
3. -5 UD* gives wrong result, with UD. as well as with D.
-3. -5 UD* gives wrong result, with UD. as well as with D.
So the correct stack comments are
UD* (ud1 u -- ud2) or (d1 n+ -- d2)
Note that "n+" is not the same as "u"; n+ is the lower 50% of range
of an unsigned number.
I consider a routine 'signed' if any of the inputs in use areexplicitly negative.
By your definition M*/ would not be signed.
This is in the eye of the beholder. In my eyes M*/ is not a fully signed
routine.
In M*/ ( d1 n1 +n2 -- d2), the divisor n2 must not be negative.
The Forth Standard allows this restriction because negative n2
does not seem to be required in typical applications.
I can live with that, although I would have preferred the requirement
( d1 n1 n2 -- d2) for reasons of consistency. Much easier to memorize.
My own rule for math operators is:
A leading "U" signals that all parameter (input and output) are unsigned
with full range of unsigned numbers.
It there is no leading "U", this signals that all parameters (input and output)
are signed with full range of signed numbers.
This is how I defined my own library of math operators, and the related
stack effects are very easy to memorize. I generally start with the unsigned >> operator. Then I define the related signed operator by calculating the overall
sign of the result first, then forming absolute values of the input parameters
and forwarding these to the unsigned routine. In the last step the overall sign
is applied to the unsigned result.
Examples: UD* ( ud1 u -- ud2 ) and D* ( d1 n -- d2) as shown in
my fist post
of this thread.
My take on this is as follows: defaults signed unless a prefix U.
Prefix U then all operands all unsigned.
A prefix M means mixed mode
* single to double (what else)
/ double single (what else)
result to single single.
Inserting a D in front op de operator:
For multiplication this make only sense for inputs, one operand goes
to double.
For division this make only sense for outputs,
as this makes no sense for the remainder as the divisor is single.
It applies to the quotient,
So at last I can remember everything.
The FIGForth M/MOD has to be renamed to UDM/MOD .
I have no patience for mixing unsigned and signed.
This is a recipe for disaster. If it were to be applicable,
I'd define a separate word in the preamble of the program,
with a ton of comment.
: * UM* DROP ;
( n1|u1 n2|u2 -- n3|u3 )
Multiply n1|u1 by n2|u2 giving the product n3|u3.
What other comment would you add?
I believe the correct stack comment is:
UD* ( d|ud1 u -- d|ud2)
: * UM* DROP ;
This is a recipe for disaster. If it were to be applicable,
I'd define a separate word in the preamble of the program,
with a ton of comment.
6.1.0090 *
star CORE
( n1|u1 n2|u2 -- n3|u3 )
Multiply n1|u1 by n2|u2 giving the product n3|u3.
What other comment would you add?
In article <u8ah70$1kadq$1@dont-email.me>, dxforth <dxforth@gmail.com> wrote:
: * UM* DROP ;
This is a recipe for disaster. If it were to be applicable,
I'd define a separate word in the preamble of the program,
with a ton of comment.
6.1.0090 *
star CORE
( n1|u1 n2|u2 -- n3|u3 )
Multiply n1|u1 by n2|u2 giving the product n3|u3.
What other comment would you add?
My concern is primarily that I remember correctly what names
I have to use. This is got to be automatic, unless productivity
suffers.
As an implementer I have a different mindset, but I don't
want thinking back to the time I have to implement these.
* works for signed and unsigned, big deal. That is not hard
to remember.
... If I don't remember what a word does,
I'd rather look it up and be certain; than try to decipher an encoded
name details of which I've likely also forgotten.
On Saturday, July 8, 2023 at 12:41:26 PM UTC+2, dxforth wrote:
... If I don't remember what a word does,
I'd rather look it up and be certain; than try to decipher an encoded
name details of which I've likely also forgotten.
I agree with that. It makes no sense to encode the full stack effect into
a word's name. This way we would end up with long and ugly word
names that no one can remember.
Word names should not only be unique and consistent.
They should also be "nice" and easy to remember.
UD* is much better than something like "UD1U--UD2*", although
the latter name describes more clearly what the word actually does.
I prefer simple names, for example:
UD* ( ud1 u -- ud2) \ unsigned double length multiplication
D* ( d1 n -- d2) \ signed double length multiplication
UT* ( ud u -- ut) \ unsigned triple length multiplication
T* ( d n -- t) \ signed triple length multiplication
UDQ* ( ud1 ud2 -- uq) \ unsigned double length multiplication with quad result
UDD* ( ud1 ud2 -- ud3) \ unsigned double length multiplication with double result
DD* ( d1 d2 -- d3) \ signed double length multiplication with double result
In case of multiplication with truncated result, the unsigned operators sometimes
also work with signed input. In this case we drop the "U" prefix from the unsigned
operator. UDD* for example handles signed numbers properly, so we can use
the simpler name DD* for this routine.
Similar naming rules can be applied to the related division operators.
And when in doubt, I don't mind looking up stack effects.
Typed languages like C don't have this kind of problem. There is only
one multiplication operand named "*". But internally this routine consists
of several subroutines for all possible cases. At compile time, the compiler decides which of these nameless subroutines should be used.
I prefer the Forth approach where the programmer decides what to do.
Even if we are sometimes forced to master the task of finding good names
for operators.
We're largely forced into it. OTOH we aren't compelled to name every conceivable multiply and division operator - only what we need. The
latter makes the task of naming simpler.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 300 |
Nodes: | 16 (2 / 14) |
Uptime: | 49:24:05 |
Calls: | 6,711 |
Calls today: | 4 |
Files: | 12,243 |
Messages: | 5,354,781 |
Posted today: | 1 |