Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

mixed double and single signed division

297 views
Skip to first unread message

krishna...@ccreweb.org

unread,
Apr 22, 2017, 11:21:50 AM4/22/17
to
Going back through to inspect the implementation of some words in kForth, I realized we added the non-standard word M/ ( d n1 -- n2 ). It turns out that though this word was available for use, it was never documented in the dictionary section of the kForth User's Guide. This led me to wondering why it was implemented in this manner, since a signed division word ( d1 n -- d2 ) seems much more useful. I have to go back and check, but I think it may have been due to M/ being specified in Leo Brodie's, Starting Forth.

ANS Forth provides M*/ which can be used to perform mixed double and single signed division; however, the divisor has to be a positive integer.

------------------------
8.6.1.1820 M*/
m-star-slash DOUBLE

( d1 n1 +n2 -- d2 )

Multiply d1 by n1 producing the triple-cell intermediate result t. Divide t by +n2 giving the double-cell quotient d2. An ambiguous condition exists if +n2 is zero or negative, or the quotient lies outside of the range of a double-precision signed integer.

See: A.8.6.1.1820 M*/
-------------------------

The appendix note A.8.6.1.1820 gives a justification of why n2 was restricted to being positive. But this imposes a burden on the programmer who simply wants to divide a signed double integer by a signed single integer, because the sign of the divisor has to be transferred to n1, which will be +1 or -1, for such an operation. Also, without the multiplication, there is no need for an intermediate triple length number. Therefore, it seems that a division word with the stack effect ( d1 n -- d2 ) would be handy. Yes, it could be implemented simply using M*/ .

Do some existing Forth implementations offer such a word, and what might be a useful name for such a word?

Krishna

NN

unread,
Apr 22, 2017, 12:15:00 PM4/22/17
to
What about FM/MOD and SM/REM ?

NN

NN

unread,
Apr 22, 2017, 12:22:56 PM4/22/17
to
On Saturday, 22 April 2017 17:15:00 UTC+1, NN wrote:
> What about FM/MOD and SM/REM ?
>
> NN

Sorry I meant to write

You probably had m/ as the basis for FM/MOD and SM/REM.

I think d/ or even m/ were not implemented because
- not used as often or if you needto you could use floats which is why I think D>F and F>D are in the standard.
- because doubles were only meant to be used when there was an overflow in the single cell range. ( my interpretation )

NN

Andrew Haley

unread,
Apr 22, 2017, 12:40:19 PM4/22/17
to
krishna...@ccreweb.org wrote:
>
> The appendix note A.8.6.1.1820 gives a justification of why n2 was
> restricted to being positive. But this imposes a burden on the
> programmer who simply wants to divide a signed double integer by a
> signed single integer, because the sign of the divisor has to be
> transferred to n1, which will be +1 or -1, for such an
> operation. Also, without the multiplication, there is no need for an
> intermediate triple length number.

Sure, but you have to do two full divisions anyway, so I don't think
that makes much difference. Whichever way you slice it, integer
division is naturally a shortening operation.

> Therefore, it seems that a division word with the stack effect ( d1
> n -- d2 ) would be handy. Yes, it could be implemented simply using
> M*/ .

I've never seen it. Its unsigned counterpart (with remainder) is
obviously useful for numeric output, but I don't know what a signed
variant would be used for.

(Are we into the "don't speculate!" argument again? :-)

Andrew.

Coos Haak

unread,
Apr 22, 2017, 5:31:55 PM4/22/17
to
Op Sat, 22 Apr 2017 09:22:55 -0700 (PDT) schreef NN:
If you have FM/MOD and/or SM/REM you can easyly write (choose one)
: M/ FM/MOD NIP ; ( d n1 -- n2 )
: M/ SM/REM NIP ; ( d n1 -- n2 )

D/ is more complex ;-)

groet Coos

HAA

unread,
Apr 22, 2017, 11:02:38 PM4/22/17
to
krishna...@ccreweb.org wrote:
> Going back through to inspect the implementation of some words in kForth, I realized we
> added the non-standard word M/ ( d n1 -- n2 ). It turns out that though this word was
> available for use, it was never documented in the dictionary section of the kForth
> User's Guide. This led me to wondering why it was implemented in this manner, since a
> signed division word ( d1 n -- d2 ) seems much more useful. I have to go back and
> check, but I think it may have been due to M/ being specified in Leo Brodie's, Starting
> Forth.
>
> ANS Forth provides M*/ which can be used to perform mixed double and single signed
> division; however, the divisor has to be a positive integer.

'Starting Forth' was polyForth where all the MOD words were unsigned. My guess is
as there was no equivalent of FM/MOD or SM/REM for users to NIP, they provided M/ .



Elizabeth D. Rather

unread,
Apr 22, 2017, 11:58:31 PM4/22/17
to
FM/MOD and SM/REM came in with Forth94, as an attempt to compromise
between warring camps wanting to mandate either floored or symmetric
division, so weren't around at the time of Starting Forth.

Cheers,
Elizabeth

--
Elizabeth D. Rather
FORTH, Inc.
6080 Center Drive, Suite 600
Los Angeles, CA 90045
USA

krishna...@ccreweb.org

unread,
Apr 23, 2017, 9:41:50 AM4/23/17
to
On Saturday, April 22, 2017 at 11:22:56 AM UTC-5, NN wrote:
> On Saturday, 22 April 2017 17:15:00 UTC+1, NN wrote:
...
>
> You probably had m/ as the basis for FM/MOD and SM/REM.
>

M/ ( d n -- nquot ) appeared in Starting Forth, 2nd edition, in its list of mixed-length operators, p. 158. This is why I implemented it in kForth. Looking at my assembly language implementation, I see that it doesn't throw an error on division overflow, i.e. when the quotient doesn't fit it into a single cell integer. This is a mistake which needs to be corrected.

> I think d/ or even m/ were not implemented because
> - not used as often or if you needto you could use floats which is why I think D>F and F>D are in the standard.
> - because doubles were only meant to be used when there was an overflow in the single cell range. ( my interpretation )
>

Double precision floats aren't equivalent, because the mantissa only has 16 significant digits. A signed double length integer on a 32-bit system has 19 significant digits, and, on a 64-bit system, about 19x9 significant digits. So, if the precision was important in your computation, double precision floats aren't a solution.

Krishna


krishna...@ccreweb.org

unread,
Apr 23, 2017, 9:44:09 AM4/23/17
to
On Saturday, April 22, 2017 at 4:31:55 PM UTC-5, Coos Haak wrote:
...
> D/ is more complex ;-)

While D/ is more complex, the mixed length division equivalent to M*/ with a multiplier of 1 or -1 will be simpler to implement.

Krishna


krishna...@ccreweb.org

unread,
Apr 23, 2017, 9:52:26 AM4/23/17
to
On Saturday, April 22, 2017 at 11:40:19 AM UTC-5, Andrew Haley wrote:
> krishna...@ccreweb.org wrote:
...
> > Therefore, it seems that a division word with the stack effect ( d1
> > n -- d2 ) would be handy. Yes, it could be implemented simply using
> > M*/ .
>
> I've never seen it. Its unsigned counterpart (with remainder) is
> obviously useful for numeric output, but I don't know what a signed
> variant would be used for.
>
> (Are we into the "don't speculate!" argument again? :-)

Speculation is good! I find myself using double length integers (on a 32-bit system) with greater frequency, and this question came up in the context of reviewing the available standard words for double number and mixed length arithmetic. While I'm fairly sure I can devise uses for such a word, I haven't yet had the need to use it myself.

Krishna

krishna...@ccreweb.org

unread,
Apr 23, 2017, 9:55:08 AM4/23/17
to
On Saturday, April 22, 2017 at 10:02:38 PM UTC-5, HAA wrote:
...
> 'Starting Forth' was polyForth where all the MOD words were unsigned. My guess is
> as there was no equivalent of FM/MOD or SM/REM for users to NIP, they provided M/ .

Yes, Starting Forth has UM/MOD but no signed equivalent.

Krishna

hughag...@gmail.com

unread,
Apr 23, 2017, 4:24:10 PM4/23/17
to
\ ******
\ ****** This is the first section, which provides UD/MOD.
\ ******

: LPswap ( d1 d2 d3 d4 -- d3 d4 d1 d2 )
>r >r 2swap >r >r 2swap r> r> r> r> 2swap
>r >r 2swap r> r> ;

: LPdup ( d1 d2 -- d1 d2 d1 d2 )
2dup >r >r 2over r> r> ;

: LPover ( d1 d2 d3 d4 -- d1 d2 d3 d4 d1 d2 )
>r >r >r >r LPdup r> r> r> r> LPswap ;

: LProt ( d1 d2 d3 d4 d5 d6 -- d3 d4 d5 d6 d1 d2 )
>r >r >r >r LPswap r> r> r> r> LPswap ;

: LPdrop ( d1 d2 -- )
drop drop drop drop ;

: um/ ( ud un -- un ) \ divide UD by UN and drop remainder
um/mod swap drop ;

: u*/ ( Umultiplier Udividend Udivisor -- Uquotient )
>r um* r> um/mod nip ;

: t* ( ud un -- ut )
dup rot um* >r >r
um*
0 r> r> d+ ;

: t/ ( ut un -- ud )
>r r@ um/mod swap
rot 0 r@ um/mod swap
rot r> um/mod swap drop
0 2swap swap d+ ;

: ut*/ ( ud un un -- ud ) \ this was called U*/ in Grossman's article, but I'm already using that name
>r t* r> t/ ;

: d- ( d1 d2 -- d1-d2 )
dnegate d+ ;

: narrow-ud/mod ( UDividend UNdivisor -- UDremainder UDquotient )
drop >r 2dup r@ \ shuck high cell of divisor
1 swap ut*/ \ -- UDquotient
2swap 2over r> 1 ut*/ d- 2swap ; \ -- UDrem UDquot

variable numH
variable denH
variable denL
variable denscale
2variable num
2variable den
0 1 2constant superbase \ this was 65536. in Grossman's article

: us>d \ convert unsigned single-cell to double-cell
0 ;

: ud/mod-tuck ( ud ud -- ) \ save parts of num and den
2dup den 2! denH ! denL !
2dup num 2! numH ! drop ;

: ud/mod-denscale ( -- un ) \ for scaling-up den
superbase denH @ 1+ um/
denscale ! ;

: scale-den ( -- ) \ multiply denominator by scale factor
den 2@ denscale @ 1 ut*/
denH ! denL ! ;

: wide-quot ( -- ud ) \ if divisor needs more than one cell
num 2@ numH @ us>d
denL @ denH @ ut*/ d-
denscale @ denH @ ut*/ swap drop ;

: ?narrow-divisor ( d -- ? ) \ is divisor < superbase?
dup 0= ;

: wide-rem ( -- ud ) \ remainder in wide division
dup num 2@ rot den 2@
rot 1 ut*/ d- rot us>d ;

: wide-ud/mod ( UDdividend UDdivisor -- UDremainder UDquotient )
ud/mod-tuck
ud/mod-denscale
scale-den
wide-quot
wide-rem ;

: ud/mod ( UDdividend UDdivisor -- UDremainder UDquotient )
?narrow-divisor if narrow-ud/mod
else wide-ud/mod then ;

: udmod ( UDdividend UDdivisor -- UDremainder )
ud/mod 2drop ;

: ud/ ( UDdividend UDdivisor -- UDquotient )
ud/mod 2swap 2drop ;


krishna...@ccreweb.org

unread,
Apr 23, 2017, 4:29:07 PM4/23/17
to
On Sunday, April 23, 2017 at 8:41:50 AM UTC-5, krishna...@ccreweb.org wrote:
> ...
> ... A signed double length integer on a 32-bit system has 19 significant digits, and, on a 64-bit system, about 19x9 significant digits. So, if the precision was important in your computation, double precision floats aren't a solution.
>

A signed double length integer on a 64-bit system, which has 128 bits, has 39 significant decimal digits, not 19x9.

KM

krishna...@ccreweb.org

unread,
Apr 23, 2017, 4:36:17 PM4/23/17
to
On Saturday, April 22, 2017 at 10:58:31 PM UTC-5, Elizabeth D. Rather wrote:
...
>
> FM/MOD and SM/REM came in with Forth94, as an attempt to compromise
> between warring camps wanting to mandate either floored or symmetric
> division, so weren't around at the time of Starting Forth.
> ...


It's also worth noting that FM/MOD and SM/REM have undefined behavior ("ambiguous condition") when the quotient overflows a single length integer. In practice, on most Forth systems, I'm guessing that a program will fail silently, unless the program is specifically written to catch the overflow.

KM

6.1.1561 FM/MOD
f-m-slash-mod CORE

( d1 n1 -- n2 n3 )

Divide d1 by n1, giving the floored quotient n3 and the remainder n2. Input and output stack arguments are signed. An ambiguous condition exists if n1 is zero or if the quotient lies outside the range of a single-cell signed integer.

6.1.2214 SM/REM
s-m-slash-rem CORE

( d1 n1 -- n2 n3 )

Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2. Input and output stack arguments are signed. An ambiguous condition exists if n1 is zero or if the quotient lies outside the range of a single-cell signed integer.



Elizabeth D. Rather

unread,
Apr 23, 2017, 7:30:42 PM4/23/17
to
That's because no one suggested any likely application scenarios that
benefit from or require a signed M/MOD. Most of the time when you
dealing with a MOD you're doing something inherently unsigned.

krishna...@ccreweb.org

unread,
Apr 23, 2017, 7:33:44 PM4/23/17
to
On Sunday, April 23, 2017 at 3:36:17 PM UTC-5, krishna...@ccreweb.org wrote:
...
> It's also worth noting that FM/MOD and SM/REM have undefined behavior ("ambiguous condition") when the quotient overflows a single length integer. In practice, on most Forth systems, I'm guessing that a program will fail silently, unless the program is specifically written to catch the overflow.
> ...

Also, UM/MOD has undefined behavior under the same conditions. Interestingly, in kForth, I perform an overflow check for UM/MOD, but not for FM/MOD or SM/REM. The latter result in a crash out of the Forth system, while the former case is handled with an error message and does not result in an ungraceful ejection from the Forth environment -- the cost is an extra division test. Here's the behavior from within kForth:

------------------------
ok
c" 40000000000" number? drop 2constant FORTY_BILLION
ok
FORTY_BILLION 2 FM/MOD
Floating point exception (core dumped)
$ ( back to OS terminal prompt )

...

FORTY_BILLION 2 SM/REM
Floating point exception (core dumped)
$ ( back to OS terminal prompt )

...

FORTY_BILLION 2 UM/MOD
Line 2: VM Error(20): Division overflow
FORTY_BILLION 2 UM/MOD

ok

( we remain within the Forth environment without adverse side effects ).
---------------------

Incidentally, I don't know the reason for giving a floating point exception error here, since no floating point operations are being performed when the exception occurs.

For the case of UM/MOD there is a check before carrying out the division. In the assembly code below, LDSP is a macro which loads TOS into the ebx register and INC_DSP adds the cell size to ebx.

L_umslashmod:
# Divide unsigned double length by unsigned single length to
# give unsigned single quotient and remainder. A "Divide overflow"
# error results if the quotient doesn't fit into a single word.
LDSP
movl $WSIZE, %eax
addl %eax, %ebx
STSP
movl (%ebx), %ecx
cmpl $0, %ecx
jz E_div_zero
addl %eax, %ebx
movl $0, %edx
movl (%ebx), %eax
divl %ecx <-- explicit check for overflow condition
cmpl $0, %eax
jne E_div_overflow
...






krishna...@ccreweb.org

unread,
Apr 23, 2017, 7:45:46 PM4/23/17
to
On Sunday, April 23, 2017 at 6:30:42 PM UTC-5, Elizabeth D. Rather wrote:
> On 4/23/17 3:55 AM, krishna...@ccreweb.org wrote:
...
> >
> > Yes, Starting Forth has UM/MOD but no signed equivalent.
>
> That's because no one suggested any likely application scenarios that
> benefit from or require a signed M/MOD. Most of the time when you
> dealing with a MOD you're doing something inherently unsigned.
> ...

That's why FM/MOD and SM/REM were introduced. My point, and that of HAA, was that at the time of Starting Forth, 2nd ed., there was no equivalent to these two words.

Krishna


HAA

unread,
Apr 23, 2017, 8:57:01 PM4/23/17
to
Elizabeth D. Rather wrote:
> On 4/23/17 3:55 AM, krishna...@ccreweb.org wrote:
> > On Saturday, April 22, 2017 at 10:02:38 PM UTC-5, HAA wrote:
> > ...
> >> 'Starting Forth' was polyForth where all the MOD words were unsigned. My guess is
> >> as there was no equivalent of FM/MOD or SM/REM for users to NIP, they provided M/ .
> >
> > Yes, Starting Forth has UM/MOD but no signed equivalent.
>
> That's because no one suggested any likely application scenarios that
> benefit from or require a signed M/MOD. Most of the time when you
> dealing with a MOD you're doing something inherently unsigned.
>
> Cheers,
> Elizabeth

Hard to believe you've never encountered situations involving a negative
dividend, positive divisor, requiring a positive mod.

That was the impetus behind the Forth-83 floored-division sweep. It's
just that they went overboard with the idea and ignored realities such as
conventional and hardware division.



Elizabeth D. Rather

unread,
Apr 23, 2017, 9:06:23 PM4/23/17
to
On 4/23/17 2:56 PM, HAA wrote:
> Elizabeth D. Rather wrote:
>> On 4/23/17 3:55 AM, krishna...@ccreweb.org wrote:
>>> On Saturday, April 22, 2017 at 10:02:38 PM UTC-5, HAA wrote:
>>> ...
>>>> 'Starting Forth' was polyForth where all the MOD words were unsigned. My guess is
>>>> as there was no equivalent of FM/MOD or SM/REM for users to NIP, they provided M/ .
>>>
>>> Yes, Starting Forth has UM/MOD but no signed equivalent.
>>
>> That's because no one suggested any likely application scenarios that
>> benefit from or require a signed M/MOD. Most of the time when you
>> dealing with a MOD you're doing something inherently unsigned.
>>
>> Cheers,
>> Elizabeth
>
> Hard to believe you've never encountered situations involving a negative
> dividend, positive divisor, requiring a positive mod.

Which ones have you encountered in your work?

> That was the impetus behind the Forth-83 floored-division sweep. It's
> just that they went overboard with the idea and ignored realities such as
> conventional and hardware division.

Yes, they were all theory-based.

hughag...@gmail.com

unread,
Apr 23, 2017, 10:10:04 PM4/23/17
to
On Sunday, April 23, 2017 at 6:06:23 PM UTC-7, Elizabeth D. Rather wrote:
> On 4/23/17 2:56 PM, HAA wrote:
> > Elizabeth D. Rather wrote:
> >> That's because no one suggested any likely application scenarios that
> >> benefit from or require a signed M/MOD. Most of the time when you
> >> dealing with a MOD you're doing something inherently unsigned.
> >
> > Hard to believe you've never encountered situations involving a negative
> > dividend, positive divisor, requiring a positive mod.
>
> Which ones have you encountered in your work?

: dow { month day year | K J -- str } \ Zeller's Algorithm: http://calendars.wikia.com/wiki/Zeller's_congruence
month 3 < if 12 +to month -1 +to year then
year 100 /mod to J to K
month 1 + 13 * 5 /
day +
K +
K 4 / +
J 4 / +
J 5 * +
1 - 7 mod days ;

Paul Rubin

unread,
Apr 23, 2017, 10:12:11 PM4/23/17
to
"Elizabeth D. Rather" <era...@forth.com> writes:
> Which ones have you encountered in your work?

This happens all the time. Like it's currently April (the 4th month of
the year) and suppose you want to know what month it was 6 months ago.
With floored mod, (4-6) mod 12 is 10, so it was October. With signed
mod, it was the month -2, which is less informative.

Elizabeth D. Rather

unread,
Apr 23, 2017, 10:31:43 PM4/23/17
to
If I wanted to know that, there are many easier ways than computing it
that way. I'm looking for a real-world example, preferably one that
you've encountered.

HAA

unread,
Apr 23, 2017, 10:59:30 PM4/23/17
to
Elizabeth D. Rather wrote:
> On 4/23/17 2:56 PM, HAA wrote:
> > Elizabeth D. Rather wrote:
> >> On 4/23/17 3:55 AM, krishna...@ccreweb.org wrote:
> >>> On Saturday, April 22, 2017 at 10:02:38 PM UTC-5, HAA wrote:
> >>> ...
> >>>> 'Starting Forth' was polyForth where all the MOD words were unsigned. My guess is
> >>>> as there was no equivalent of FM/MOD or SM/REM for users to NIP, they provided M/ .
> >>>
> >>> Yes, Starting Forth has UM/MOD but no signed equivalent.
> >>
> >> That's because no one suggested any likely application scenarios that
> >> benefit from or require a signed M/MOD. Most of the time when you
> >> dealing with a MOD you're doing something inherently unsigned.
> >>
> >> Cheers,
> >> Elizabeth
> >
> > Hard to believe you've never encountered situations involving a negative
> > dividend, positive divisor, requiring a positive mod.
>
> Which ones have you encountered in your work?
>
> > That was the impetus behind the Forth-83 floored-division sweep. It's
> > just that they went overboard with the idea and ignored realities such as
> > conventional and hardware division.
>
> Yes, they were all theory-based.
>
> Cheers,
> Elizabeth

Convert number to engineering notation.
exp' = new exponent, mod = #places to shift decimal point.

: >eng ( exp -- mod exp' ) s>d 3 fm/mod 3 * ;

: test -10 10 do cr i 4 .r i >eng 4 .r 4 .r -1 +loop ;

test
10 9 1
9 9 0
8 6 2
7 6 1
6 6 0
5 3 2
4 3 1
3 3 0
2 0 2
1 0 1
0 0 0
-1 -3 2
-2 -3 1
-3 -3 0
-4 -6 2
-5 -6 1
-6 -6 0
-7 -9 2
-8 -9 1
-9 -9 0
-10 -12 2 ok



Elizabeth D. Rather

unread,
Apr 24, 2017, 12:03:15 AM4/24/17
to
You've actually done this in an application, or is this just another
hypothetical? The number conversions I've seen don't do it that way.

hughag...@gmail.com

unread,
Apr 24, 2017, 12:17:11 AM4/24/17
to
On Sunday, April 23, 2017 at 7:31:43 PM UTC-7, Elizabeth D. Rather wrote:
> On 4/23/17 4:12 PM, Paul Rubin wrote:
> > "Elizabeth D. Rather" <era...@forth.com> writes:
> >> Which ones have you encountered in your work?
> >
> > This happens all the time. Like it's currently April (the 4th month of
> > the year) and suppose you want to know what month it was 6 months ago.
> > With floored mod, (4-6) mod 12 is 10, so it was October. With signed
> > mod, it was the month -2, which is less informative.
>
> If I wanted to know that, there are many easier ways than computing it
> that way. I'm looking for a real-world example, preferably one that
> you've encountered.

Elizabeth Rather wants to ban anything that hasn't been used in a Forth Inc. application program. This is why double-precision division was banned from ANS-Forth --- nobody at Forth Inc. at run into the need for it --- then in the year 2009 I need it for my continued-fraction program (actually Nathaniel Grossman needed it in 1984) and her solution is to say that I'm not a Forth programmer and can never become a Forth programmer because I don't understand the Forth Way.

ANS-Forth is a cult! Elizabeth Rather's contribution has been purely negative --- all she does is tell Forth programmers what they can't do --- also, the Forth-200x committee (the "Committee of Can't") that she appointed does the same thing (ban my rquotations as non-standard, although they work under VFX and SwiftForth and could be made to work under almost any Forth system).

hughag...@gmail.com

unread,
Apr 24, 2017, 12:22:01 AM4/24/17
to
Show us your code! You apparently are an expert on converting numbers into strings --- let us see your wonderful code! --- you are just telling lies again; you don't have any code...

This is my code from the novice-package:
-------------------------------------------------------------------------

\ ******
\ ****** The following is for numeric output.
\ ******

: comma ( d -- d )
[char] , hold ;

: dot ( d -- d )
[char] . hold ;

: _# ( d -- d_less_digit ) \ digit if number is non-zero, else a blank
2dup d0= if bl hold else # then ;

: _comma ( d -- d ) \ comma if number is non-zero, else a blank
2dup d0= if bl hold else comma then ;

\ _# and _comma are used to blank-out the leftmost of the number if the digits are zero.

: book-sign ( d neg? -- d )
if [char] - else [char] + then hold ;

\ This is a bookkeeping-style sign. It prints a + for positive rather than print nothing.

item ?sgn \ used by ?# and ?COMMA

: ?# ( d -- new-d ) \ needs ?SGN set \ similar to _# except puts a - in there if ?SGN is set
2dup d0= if
?sgn if ?sgn sign then
false to ?sgn
else
# then ;

: ?comma ( d -- d ) \ needs ?SGN set \ similar to _comma except puts a - in there if ?SGN is set
2dup d0= if
?sgn if ?sgn sign then
false to ?sgn
else
comma then ;

: <big.> ( d -- adr cnt ) \ used for big numbers that need commas for clarity
2dup d0< to ?sgn dabs
<#
# ?# ?# ?comma
?# ?# ?# ?comma
?# ?# ?# ?comma
?# ?# ?# ?comma
?# ?# ?# ?comma
?# ?# ?# ?comma
?#
#> ;

: big. ( d -- )
<big.> type ;

item ~#soft \ TRUE implies that ~# shouldn't output zeros

: ~# ( Da -- Db ) \ needs ~#SOFT set
~#soft if
2dup 10 um/mod drop if # false to ~#soft
else 1 10 m*/ then
else
# then ;

: ~. ( D -- D ) \ needs ~#SOFT set
~#soft not if [char] . hold then ;

\ ~# is used for the digits to the right of the decimal point.
\ ~. is used for the decimal point.

: round-off { prec -- } \ float: n -- new-n
prec 1 ?do 10.e f* loop fnear
prec 1 ?do 10.e f/ loop ;

: adjust-down ( adjustment -- new-adjustment ) \ float: n -- new-n
begin fdup 10.e f>= while
10.e f/ 1+ repeat ;

: adjust-up ( adjustment -- new-adjustment ) \ float: n -- new-n
begin fdup 1.e f< while
10.e f* 1- repeat ;

: exponent { prec | sgn -- adjustment } \ float: n -- new-n
0 \ -- adjustment
fdup f0= if exit then
fdup f0< to sgn fabs
adjust-up
adjust-down prec round-off adjust-down
sgn if fnegate then ;

: #exponent ( n -- ) \ must be called from within <# #>
?dup if
dup >r abs 0 \ -- d
#s r> sign [char] e hold \ -- d0
2drop then ;

: <scientific> { prec engineering? | sgn exp -- adr cnt } \ float: n --
prec 1 < abort" *** F>STRING needs a precision parameter >= 1 ***"
prec exponent to exp
engineering? if
begin exp 3 mod while 10.e f* -1 +to exp -1 +to prec repeat
fdup fabs prec round-off
1000.e f>= if 1000.e f/ 3 +to exp 3 +to prec then
then
prec 1 ?do 10.e f* loop
fnear f>d
dup to sgn dabs <# bl hold
exp #exponent
true to ~#soft prec 1 ?do ~# loop ~.
2dup or if #s
else ~#soft if #s then then
sgn sign #> ;

\ The e is optional, which prevents these numbers from being used in Forth source-code. >FLOAT still works though.

10 constant max-prec \ 11 works sometimes, but fails if the most significant digit is large. 10 always works.

: scientific ( -- adr cnt ) \ float: n --
precision false <scientific> ;

: max-scientific ( -- adr cnt ) \ float: n --
max-prec false <scientific> ;

: engineering ( -- adr cnt ) \ float: n --
precision true <scientific> ;

: max-engineering ( -- adr cnt ) \ float: n --
max-prec true <scientific> ;

2000000001 constant eng-lim \ must be a positive integer
\ In <ENG> any float >= the lim goes to ENGINEERING and otherwise is done without an 'e'

: <eng> ( -- adr cnt lim ) \ float: n --
fdup fabs s>d d>f f>= fdup fabs 1e f< or if engineering exit then
<cstr
fdup f0< if [char] - char+cstr then
fabs
fdup f>d 2dup <big.> <+cstr>
d>f f- \ float: integer-part
fdup f0= 0= if
[char] . char+cstr
precision 0 ?do 10.e f* loop
true to ~#soft
fround f>d <# precision 0 ?do ~# loop #> <+cstr>
then
cstr> count ;

: eng ( -- adr cnt ) \ float: n --
eng-lim <eng> ;

: HOLDS ( adr len -- ) \ HOLD a string
BEGIN DUP WHILE 1- 2DUP CHARS + C@ HOLD REPEAT 2DROP ;

\ HOLDS was written by HAA (he called it $HOLD though): https://groups.google.com/forum/#!topic/comp.lang.forth/ictps0w02yk

Paul Rubin

unread,
Apr 24, 2017, 12:47:25 AM4/24/17
to
"Elizabeth D. Rather" <era...@forth.com> writes:
> If I wanted to know that, there are many easier ways than computing it
> that way

What would be an example of an easier way? It should work for 6 months
earlier, 73 months earlier, 62 months later, etc.

hughag...@gmail.com

unread,
Apr 24, 2017, 1:58:01 AM4/24/17
to
What I have in the novice-package doesn't exactly do that, because it adds days to a particular date, not months --- months vary in the number of days that they have --- so, your code is actually necessary (I'll put it in the novice-package).

This is what I have in the novice-package at this time:
-------------------------------------------------------

\ ******
\ ****** This is the day of the week calculator.
\ ******

align here ," Saturday"
align here ," Friday"
align here ," Thursday"
align here ," Wednesday"
align here ," Tuesday"
align here ," Monday"
align here ," Sunday"

create <days> , , , , , , , \ Sunday=0, Monday=1, ... Saturday=6

: days ( n -- str )
dup 0< over 7 >= or abort" *** DAYS given invalid value ***"
w * <days> + @ ;

\ See TOY.4TH for two more implementations, one of which is my own invention.

\ DATE>N and N>DATE both come from: https://alcor.concordia.ca//~gpkatch/gdate-algorithm.html
\ This is mostly useful when you need add some number of days to a date and get a new date.

: date>n { month day year -- n }
month 9 + 12 mod to month
year month 10 / - to year
year 365 *
year 4 / +
year 100 / -
year 400 / +
month 306 * 5 + 10 / +
day 1 - + ;

: n>dow ( n -- str ) \ N comes from DATE>N
3 + 7 mod days ;

: n>date { n | y mm dd ddd mi -- month day year } \ N comes from DATE>N
n 10000 um* 14780. d+ 3652425 um/mod nip to y
365 y * y 4 / + y 100 / - y 400 / + n swap - to ddd
ddd 0< if
y 1 - to y
365 y * y 4 / + y 100 / - y 400 / + n swap - to ddd then
ddd 100 * 52 + 3060 / to mi
mi 2 + 12 mod 1 + to mm
mi 2 + 12 / y + to y
mi 306 * 5 + 10 / ddd swap - 1 + to dd
mm dd y ;

: valid-date? ( month day year -- flag )
3dup date>n n>date \ -- m1 d1 y1 m2 d2 y2
fourth = >r \ -- m1 d1 y1 m2 d2
fourth = >r \ -- m1 d1 y1 m2
fourth = >r \ -- m1 d1 y1
3drop
r> r> and r> and ;

hughag...@gmail.com

unread,
Apr 24, 2017, 2:22:51 AM4/24/17
to
On Sunday, April 23, 2017 at 10:58:01 PM UTC-7, hughag...@gmail.com wrote:
> On Sunday, April 23, 2017 at 9:47:25 PM UTC-7, Paul Rubin wrote:
> > "Elizabeth D. Rather" <era...@forth.com> writes:
> > > If I wanted to know that, there are many easier ways than computing it
> > > that way
> >
> > What would be an example of an easier way? It should work for 6 months
> > earlier, 73 months earlier, 62 months later, etc.
>
> What I have in the novice-package doesn't exactly do that, because it adds days to a particular date, not months --- months vary in the number of days that they have --- so, your code is actually necessary (I'll put it in the novice-package).

I just noticed that you didn't provide any code. So I wrote it myself. Here is the addition I'll put in the novice-package:

: month+ ( month n -- relative-year new-month ) \ MONTH and NEW-MONTH are in the range [1,12]
+ 1- s>d \ the 1- is because we need months in the range [0,11]
12 fm/mod
swap 1+ ;

\ MONTH+ was inspired by Paul Rubin in this thread: https://groups.google.com/forum/#!topic/comp.lang.forth/i_F7GtPxjE4

Andrew Haley

unread,
Apr 24, 2017, 5:46:21 AM4/24/17
to
Elizabeth D. Rather <era...@forth.com> wrote:
> On 4/23/17 4:12 PM, Paul Rubin wrote:
>> "Elizabeth D. Rather" <era...@forth.com> writes:
>>> Which ones have you encountered in your work?
>>
>> This happens all the time. Like it's currently April (the 4th month of
>> the year) and suppose you want to know what month it was 6 months ago.
>> With floored mod, (4-6) mod 12 is 10, so it was October. With signed
>> mod, it was the month -2, which is less informative.
>
> If I wanted to know that, there are many easier ways than computing it
> that way. I'm looking for a real-world example, preferably one that
> you've encountered.

The classic one is an angle of rotation, which can lead or lag and
sometimes even exceed 360 degrees, and I have encountered that in real
life. But if the dividend is negative and all you want is the
remainder, all you have to do is add a multiple of the divisor into
the dividend. The easiest way to do that is to add the dividend into
the high cell of the divisor and then do the division.

I believe that the argument circa 1981 was about whether MOD words
which can to handle negative dividends should be part of the standard
word set, rather that whether they were occasionally useful. On the
other hand, I am happy to maintain that calculating the remainder of
anything mod N, N < 0 makes no sense.

Andrew.

Anton Ertl

unread,
Apr 24, 2017, 9:23:17 AM4/24/17
to
krishna...@ccreweb.org writes:
>On Saturday, April 22, 2017 at 10:58:31 PM UTC-5, Elizabeth D. Rather wrote=
>:
>...
>>=20
>> FM/MOD and SM/REM came in with Forth94, as an attempt to compromise=20
>> between warring camps wanting to mandate either floored or symmetric=20
>> division, so weren't around at the time of Starting Forth.
>> ...
>
>
>It's also worth noting that FM/MOD and SM/REM have undefined behavior ("amb=
>iguous condition") when the quotient overflows a single length integer.

Note that an ambiguous condition in the Forth standard is more like
"implementation-defined" behaviour than "undefined behaviour" in the C
standard. A standard system is required to document what happens on
undefined behaviour, and time-travel is not part of the Forth standard
(but it is part of the C standard).

>In =
>practice, on most Forth systems, I'm guessing that a program will fail sile=
>ntly, unless the program is specifically written to catch the overflow.

On IA-32 and AMD64, division overflow and dividing by zero produces a
CPU exception. On a number of other CPUs, you just get some result.
Forth systems typically just do what the CPU does, but gforth (not
gforth-fast) produces a Forth exception for both conditions even on
CPUs where the hardware does not produce exceptions itself.

- 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: http://www.forth200x.org/forth200x.html
EuroForth 2016: http://www.euroforth.org/ef16/

Anton Ertl

unread,
Apr 24, 2017, 9:59:27 AM4/24/17
to
krishna...@ccreweb.org writes:
>The latter result in a crash out of the Forth system, while the fo=
>rmer case is handled with an error message and does not result in an ungrac=
>eful ejection from the Forth environment -- the cost is an extra division t=
>est.

If all you want is to suppress the signal, you can just set SIGFPE to SIG_IGN.

>c" 40000000000" number? drop 2constant FORTY_BILLION
> ok
>FORTY_BILLION 2 FM/MOD
>Floating point exception (core dumped)
>$ ( back to OS terminal prompt )
...
>Incidentally, I don't know the reason for giving a floating point exception=
> error here, since no floating point operations are being performed when th=
>e exception occurs.

My guess is that you are running a Unix. Unix reports integer
overflows and other integer computation errors through SIGFPE (my
guess is that when they designed signals, they had hardware which had
FP exceptions, but no integer exceptions, so they did not introduce a
SIGINTE).

If you catch the signal, you can use the si_code field of the siginfor
struct to find out what the cause of the signal was. E.g., if it is
FPE_INTDIV, it's an integer division by zero (and, as we will see,
possibly other integer division errors). Gforth does all that, and
therefore you get, on AMD64:

1 0 /
:1: Division by zero
1 0 >>>/<<<
Backtrace:
0 1 1 um/mod .s
:2: Division by zero
0 1 1 >>>um/mod<<< .s
Backtrace:

Looking up
<http://x86.renejeschke.de/html/file_module_x86_id_72.html>, I see
that both division by zero and an out-of-range result produce a DE
(divide exception) on AMD64. I guess Linux just translates this into
FPE_INTDIV, without differentiationg between division by zero and the
other cases.

krishna...@ccreweb.org

unread,
Apr 24, 2017, 9:35:55 PM4/24/17
to
On Monday, April 24, 2017 at 8:23:17 AM UTC-5, Anton Ertl wrote:
> krishna...@ccreweb.org writes:
...
> >It's also worth noting that FM/MOD and SM/REM have undefined behavior ("ambiguous condition") when the quotient overflows a single length integer.
>
> Note that an ambiguous condition in the Forth standard is more like
> "implementation-defined" behaviour than "undefined behaviour" in the C
> standard. A standard system is required to document what happens on
> undefined behaviour, and time-travel is not part of the Forth standard
> (but it is part of the C standard).
>

I'm having trouble seeing the practical difference between "implementation-defined" behavior and "undefined behavior" -- the behavior of a given implementation for the condition will be specifiable.

> >In practice, on most Forth systems, I'm guessing that a program will fail silently, unless the program is specifically written to catch the overflow.
>
> On IA-32 and AMD64, division overflow and dividing by zero produces a
> CPU exception. On a number of other CPUs, you just get some result.
> Forth systems typically just do what the CPU does, but gforth (not
> gforth-fast) produces a Forth exception for both conditions even on
> CPUs where the hardware does not produce exceptions itself.
>

I would consider that sane behavior, at least on a desktop system. Perhaps there are reasons why garbage answers should be allowed to propagate in the subsequent computations on an embedded system, but I have difficulty seeing how that could be benign. For all of my computing, it's necessary to know if an arithmetic overflow condition exists, in the form of a program halt and a diagnostic message stating the condition. Sure, it will likely show up as grossly incorrect answers if there was no exception, but perhaps not under some conditions.

This brings up the question of other arithmetic overflow. For the case of addition and subtraction on two's complement arithmetic, there is wrapping behavior, without a processor exception, and this behavior is widely expected and maybe even utilized. However, for multiplication, say of two single length integers, we could easily get an arithmetic overflow condition which also does not generate an exception but wraps, e.g.

-1 1 lshift 1 rshift constant MAX_N

MAX_N 4 *

On a 32-bit system, MAX_N is 2147483647 and multiplying by 4 gives -4 for a single length result. This is clearly wrapping behavior, as a result of taking only the lower dword of the product. The x86 IMUL instruction does set the carry and overflow flags, so it's easily to know when an arithmetic overflow occurred. Nevertheless, I'm guessing most Forth systems do not bother checking for an overflow on this condition. It seems to me like this condition should be important to flag to the programmer/user.

We could be safe in the above example by using M* , which means converting the first operand to a double signed integer, so that the product is a double length integer. Then, the subsequent computations would have to be done on doubles, which is probably a waste on more than 99% of the cases. But, do programmers generally have that insight, a priori, to anticipate and code for the very few cases in which an overflow might occur when multiplying two single integers together with *? I'm guessing not. It seems better, in my opinion, to have the Forth system generate an exception (throw an error) for the overflow condition involving * . Maybe this is too much hand-holding for the programmer, but I worry that these errors can be subtle and hard to detect, and any system hints are immensely valuable.

Krishna

krishna...@ccreweb.org

unread,
Apr 24, 2017, 9:49:52 PM4/24/17
to
On Monday, April 24, 2017 at 8:59:27 AM UTC-5, Anton Ertl wrote:
> krishna...@ccreweb.org writes:
> >The latter result in a crash out of the Forth system, while the former case is handled with an error message and does not result in an ungraceful ejection from the Forth environment -- the cost is an extra division test.
>
> If all you want is to suppress the signal, you can just set SIGFPE to SIG_IGN.
>

Well, this wouldn't allow me to halt the operation and report an error if the exception was ignored. I'm more interested in notification of the overflow condition, since that tells me I didn't properly anticipate the range of operands.

> >c" 40000000000" number? drop 2constant FORTY_BILLION
> > ok
> >FORTY_BILLION 2 FM/MOD
> >Floating point exception (core dumped)
> >$ ( back to OS terminal prompt )
> ...
> >Incidentally, I don't know the reason for giving a floating point exception error here, since no floating point operations are being performed when the exception occurs.
>
> My guess is that you are running a Unix. Unix reports integer
> overflows and other integer computation errors through SIGFPE (my
> guess is that when they designed signals, they had hardware which had
> FP exceptions, but no integer exceptions, so they did not introduce a
> SIGINTE).

Correct. Linux, in fact.

>
> If you catch the signal, you can use the si_code field of the siginfor
> struct to find out what the cause of the signal was. E.g., if it is
> FPE_INTDIV, it's an integer division by zero (and, as we will see,
> possibly other integer division errors). Gforth does all that, and
> therefore you get, on AMD64:
>
> 1 0 /
> :1: Division by zero
> 1 0 >>>/<<<
> Backtrace:
> 0 1 1 um/mod .s
> :2: Division by zero
> 0 1 1 >>>um/mod<<< .s
> Backtrace:
>

That's very useful debugging info!

> Looking up
> <http://x86.renejeschke.de/html/file_module_x86_id_72.html>, I see
> that both division by zero and an out-of-range result produce a DE
> (divide exception) on AMD64. I guess Linux just translates this into
> FPE_INTDIV, without differentiationg between division by zero and the
> other cases.
>

Thanks for the info on the exceptions. Catching the exception is the most efficient way, without incurring extra computation overhead. Directly coding the overflow check, rather than relying on a processor exception, is a more portable and more general method, as you point out.

Krishna

Elizabeth D. Rather

unread,
Apr 24, 2017, 9:52:06 PM4/24/17
to
On 4/24/17 3:35 PM, krishna...@ccreweb.org wrote:
> On Monday, April 24, 2017 at 8:23:17 AM UTC-5, Anton Ertl wrote:
>> krishna...@ccreweb.org writes:
> ...
>>> It's also worth noting that FM/MOD and SM/REM have undefined behavior ("ambiguous condition") when the quotient overflows a single length integer.
>>
>> Note that an ambiguous condition in the Forth standard is more like
>> "implementation-defined" behaviour than "undefined behaviour" in the C
>> standard. A standard system is required to document what happens on
>> undefined behaviour, and time-travel is not part of the Forth standard
>> (but it is part of the C standard).
>>
>
> I'm having trouble seeing the practical difference between "implementation-defined" behavior and "undefined behavior" -- the behavior of a given implementation for the condition will be specifiable.

The important distinction is that a standard system must document its
response to all "implementation *defined*" items mentioned in the
Standard. There is no such requirement on "undefined behavior".

>>> In practice, on most Forth systems, I'm guessing that a program will fail silently, unless the program is specifically written to catch the overflow.
>>
>> On IA-32 and AMD64, division overflow and dividing by zero produces a
>> CPU exception. On a number of other CPUs, you just get some result.
>> Forth systems typically just do what the CPU does, but gforth (not
>> gforth-fast) produces a Forth exception for both conditions even on
>> CPUs where the hardware does not produce exceptions itself.
>>
>
> I would consider that sane behavior, at least on a desktop system. Perhaps there are reasons why garbage answers should be allowed to propagate in the subsequent computations on an embedded system, but I have difficulty seeing how that could be benign. For all of my computing, it's necessary to know if an arithmetic overflow condition exists, in the form of a program halt and a diagnostic message stating the condition. Sure, it will likely show up as grossly incorrect answers if there was no exception, but perhaps not under some conditions.

In my experience, one does actually have a good idea of when something
might overflow. In any particular application, when you're doing
computation you have a fair idea of the range of values you're dealing
with. The most common method for dealing with potential overflow is to
apply an appropriate scale factor using M*/ (which is what it was
designed for).

> This brings up the question of other arithmetic overflow. For the case of addition and subtraction on two's complement arithmetic, there is wrapping behavior, without a processor exception, and this behavior is widely expected and maybe even utilized. However, for multiplication, say of two single length integers, we could easily get an arithmetic overflow condition which also does not generate an exception but wraps, e.g.
>
> -1 1 lshift 1 rshift constant MAX_N
>
> MAX_N 4 *
>
> On a 32-bit system, MAX_N is 2147483647 and multiplying by 4 gives -4 for a single length result. This is clearly wrapping behavior, as a result of taking only the lower dword of the product. The x86 IMUL instruction does set the carry and overflow flags, so it's easily to know when an arithmetic overflow occurred. Nevertheless, I'm guessing most Forth systems do not bother checking for an overflow on this condition. It seems to me like this condition should be important to flag to the programmer/user.
>
> We could be safe in the above example by using M* , which means converting the first operand to a double signed integer, so that the product is a double length integer. Then, the subsequent computations would have to be done on doubles, which is probably a waste on more than 99% of the cases. But, do programmers generally have that insight, a priori, to anticipate and code for the very few cases in which an overflow might occur when multiplying two single integers together with *? I'm guessing not. It seems better, in my opinion, to have the Forth system generate an exception (throw an error) for the overflow condition involving * . Maybe this is too much hand-holding for the programmer, but I worry that these errors can be subtle and hard to detect, and any system hints are immensely valuable.

Scale it using M*/, and then document that your result is in units of km
instead of meters, for example.

HAA

unread,
Apr 24, 2017, 10:54:11 PM4/24/17
to
Elizabeth D. Rather wrote:
> On 4/23/17 4:59 PM, HAA wrote:
> > Elizabeth D. Rather wrote:
> >> ...
AFAIK there is no easier way to accomplish it. If you didn't do it that
way, perhaps it's because you didn't recognize that you could.

Yes, I've used it - as does most every forth which implements f/p
engineering display.



Elizabeth D. Rather

unread,
Apr 25, 2017, 3:55:53 AM4/25/17
to
If you're using floating point, you don't care about signed MODs.

Anton Ertl

unread,
Apr 25, 2017, 5:03:12 AM4/25/17
to
krishna...@ccreweb.org writes:
>On Monday, April 24, 2017 at 8:23:17 AM UTC-5, Anton Ertl wrote:
>> krishna...@ccreweb.org writes:
>...
>> >It's also worth noting that FM/MOD and SM/REM have undefined behavior ("=
>ambiguous condition") when the quotient overflows a single length integer.
>>=20
>> Note that an ambiguous condition in the Forth standard is more like
>> "implementation-defined" behaviour than "undefined behaviour" in the C
>> standard. A standard system is required to document what happens on
>> undefined behaviour, and time-travel is not part of the Forth standard
>> (but it is part of the C standard).
>>=20
>
>I'm having trouble seeing the practical difference between "implementation-=
>defined" behavior and "undefined behavior" -- the behavior of a given imple=
>mentation for the condition will be specifiable.

One might think so, but the C standards lawyers and the gcc
maintainers make a big thing of the difference. In particular, they
treat undefined behaviour as an invitation to unleash their favourite
pets, the nasal demons, but not (yet?) for implementation-defined
behaviour.

> Perhaps =
>there are reasons why garbage answers should be allowed to propagate in the=
> subsequent computations on an embedded system, but I have difficulty seein=
>g how that could be benign.

Actually, I find the postscript behaviour of terminating on every
error pretty annoying: I need the data for all the non-erroneous cases
to come out, and for the erroneous case, nothing should be shown.
Postscript does not have something like CATCH, so I have to do input
checking on a lot of operations.

>This brings up the question of other arithmetic overflow. For the case of a=
>ddition and subtraction on two's complement arithmetic, there is wrapping b=
>ehavior, without a processor exception, and this behavior is widely expecte=
>d and maybe even utilized. However, for multiplication, say of two single l=
>ength integers, we could easily get an arithmetic overflow condition which =
>also does not generate an exception but wraps, e.g.
>
>-1 1 lshift 1 rshift constant MAX_N
>
>MAX_N 4 *=20
>
>On a 32-bit system, MAX_N is 2147483647 and multiplying by 4 gives -4 for a=
> single length result. This is clearly wrapping behavior, as a result of ta=
>king only the lower dword of the product. The x86 IMUL instruction does set=
> the carry and overflow flags, so it's easily to know when an arithmetic ov=
>erflow occurred. Nevertheless, I'm guessing most Forth systems do not bothe=
>r checking for an overflow on this condition. It seems to me like this cond=
>ition should be important to flag to the programmer/user.=20
>
>We could be safe in the above example by using M* , which means converting =
>the first operand to a double signed integer, so that the product is a doub=
>le length integer.

M* has the stack effect ( n1 n2 -- d )

> Then, the subsequent computations would have to be done =
>on doubles,

If you just want to catch the overflow case, you can do it as follows:

: n* ( n1 n2 -- n )
m* >r s>d r> <> -11 and throw ;

: u* ( u1 u2 -- u )
um* 0<> -11 and throw ;

and then use these words in your program.

>It seems better, in m=
>y opinion, to have the Forth system generate an exception (throw an error) =
>for the overflow condition involving * .

* works on signed and on unsigned numbers, and whether something is an
overflow depends on what kinds of numbers you work on, so your idea
cannot work for *.

Moreover, the current draft for the next standard specifies that *
(among others) ignores overflow and uses modulo arithmetics.
EuroForth 2017: http://www.euroforth.org/ef17/

krishna...@ccreweb.org

unread,
Apr 25, 2017, 5:18:11 AM4/25/17
to
On Monday, April 24, 2017 at 8:52:06 PM UTC-5, Elizabeth D. Rather wrote:
> On 4/24/17 3:35 PM, krishna...@ccreweb.org wrote:
...
> > I'm having trouble seeing the practical difference between "implementation-defined" behavior and "undefined behavior" -- the behavior of a given implementation for the condition will be specifiable.
>
> The important distinction is that a standard system must document its
> response to all "implementation *defined*" items mentioned in the
> Standard. There is no such requirement on "undefined behavior".
>

Ok. Thanks for the clarification.

Krishna


Paul Rubin

unread,
Apr 25, 2017, 5:25:06 AM4/25/17
to
"Elizabeth D. Rather" <era...@forth.com> writes:
> The important distinction is that a standard system must document its
> response to all "implementation *defined*" items mentioned in the
> Standard. There is no such requirement on "undefined behavior".

I don't understand the difference. Can the target system document its
response to implementation-defined item X as "doing X makes demons fly
out of your nose"? If yes, implementation-defined is no different from
UB.

krishna...@ccreweb.org

unread,
Apr 25, 2017, 5:25:57 AM4/25/17
to
On Tuesday, April 25, 2017 at 4:03:12 AM UTC-5, Anton Ertl wrote:
...
> * works on signed and on unsigned numbers, and whether something is an
> overflow depends on what kinds of numbers you work on, so your idea
> cannot work for *.
>

* is a signed multiply. I don't follow what you mean by the overflow depending on the sign of the operands. The x86 signed multiply (IMUL) instruction sets an overflow flag when overflow occurs, regardless of the sign of the operands. Doesn't the overflow flag simply mean that there are significant bits which will be discarded when the single length result is taken?

> Moreover, the current draft for the next standard specifies that *
> (among others) ignores overflow and uses modulo arithmetics.
>

Why would you do this for multiplication but not for division?

Krishna

krishna...@ccreweb.org

unread,
Apr 25, 2017, 6:00:55 AM4/25/17
to
On Tuesday, April 25, 2017 at 4:25:57 AM UTC-5, krishna...@ccreweb.org wrote:
> On Tuesday, April 25, 2017 at 4:03:12 AM UTC-5, Anton Ertl wrote:
...
> > Moreover, the current draft for the next standard specifies that *
> > (among others) ignores overflow and uses modulo arithmetics.
> >
>
> Why would you do this for multiplication but not for division?
>


The following seems inconsistent to me.

-------------------
$ gforth

-1 1 rshift constant MAX_N
MAX_N dup m* 2constant DN2

DN2 2 fm/mod

:3: Division by zero
DN2 2 >>>fm/mod<<<
Backtrace:

MAX_N dup *
.
1
-----------------

The division error is, of course, not divide by zero, but division overflow. Why should division overflow result in an abortive error condition with a warning message, but not overflow on multiplication? Both seem to me equally dangerous error conditions.

Krishna






HAA

unread,
Apr 25, 2017, 6:00:56 AM4/25/17
to
You care about printing f/p numbers in engineering format. Below is the
code from SwiftForth's fpmath.f using floored division to adjust the exponent:

: Adjust ( n - n' 1|2|3 )
S>D 3 FM/MOD 3 * SWAP 1+ ;

Here's another practical use of floored division. You need to increment
or decrement date/time by seconds. Floored division does this easily:

\ increment or decrement stored date/time in seconds
: +SECONDS ( secs -- )
seconds @ + s>d secs/day fm/mod jdays +! seconds ! ;





Anton Ertl

unread,
Apr 25, 2017, 7:37:07 AM4/25/17
to
Paul Rubin <no.e...@nospam.invalid> writes:
>I don't understand the difference. Can the target system document its
>response to implementation-defined item X as "doing X makes demons fly
>out of your nose"?

That would define the behaviour, too. But yes, I have come across a
posting that said that the implementation can define a particular
implementation-defined behaviour to be undefined.

And my guess is that, at one point, the gcc and clang maintainers will
no longer be content with "optimizing" based on the assumption that
the program undefined does not contain undefined behaviour, and then
they will also "optimize" based on the assumption that
implementation-defined behaviour does not happen. And they will have
language lawyers and fanboys who will support them in that position.
EuroForth 2017: http://www.euroforth.org/ef17/

Anton Ertl

unread,
Apr 25, 2017, 8:01:45 AM4/25/17
to
krishna...@ccreweb.org writes:
>On Tuesday, April 25, 2017 at 4:03:12 AM UTC-5, Anton Ertl wrote:
>...
>> * works on signed and on unsigned numbers, and whether something is an
>> overflow depends on what kinds of numbers you work on, so your idea
>> cannot work for *.
>>=20
>
>* is a signed multiply.

From the standard:

|* ( n1 | u1 n2 | u2 -- n3 | u3 )
|
|Multiply n1 | u1 by n2 | u2 giving the product n3 | u3.

> I don't follow what you mean by the overflow depend=
>ing on the sign of the operands.

-1 -1 * is an overflow when you view it as an unsigned operation, but not when you view it as a signed operation.

$ffff $ffff * is an overflow on a 32-bit system when you view it as
signed operation but not when you view it as unsigned operation.

>> Moreover, the current draft for the next standard specifies that *
>> (among others) ignores overflow and uses modulo arithmetics.
>>=20
>
>Why would you do this for multiplication but not for division?

We don't do it for division for several reasons:

1) No hardware implements modulo arithmetic for division (and IIRC
that would only be defined for odd divisors anyway), and even if it
did, programs would probably usually prefer division-with-remainder.

2) Hardware diverges for division: There is hardware that produces an
exception for certain inputs, and hardware that doesn't.

By contrast, for *, all recent hardware that has a multiplication
instruction has one that does not produce an exception.
Modulo-arithmetic * is also an important operation in computing hash
functions. And if you want to be sure that there is no overflow, you
can make sure with M* or UM*.

krishna...@ccreweb.org

unread,
Apr 25, 2017, 8:27:39 AM4/25/17
to
While rationale 1) is weak, I think reasons 2) and the unnumbered 3) no recent multiplication hardware that generates overflow exceptions, and 4) modulo multiplication is useful for hash functions are fairly strong reasons. I suggest documenting these reasons in the appendix.

> And if you want to be sure that there is no overflow, you
> can make sure with M* or UM*.
>

I'm considering implementing a separate "safe" multiply operator for single length operands, which will throw an error on overflow, with an appropriate diagnostic message. Clearly, the programmer did not intend for the multiply to overflow, and should have the opportunity to be informed of it so that the code can be fixed.

Krishna


Coos Haak

unread,
Apr 25, 2017, 9:32:17 AM4/25/17
to
Op Mon, 24 Apr 2017 18:35:53 -0700 (PDT) schreef
krishna...@ccreweb.org:

> On Monday, April 24, 2017 at 8:23:17 AM UTC-5, Anton Ertl wrote:
<snip>
> This brings up the question of other arithmetic overflow. For the case of addition and subtraction on two's complement arithmetic, there is wrapping behavior, without a processor exception, and this behavior is widely expected and maybe even utilized. However, for multiplication, say of two single length integers, we could easily get an arithmetic overflow condition which also does not generate an exception but wraps, e.g.
>
> -1 1 lshift 1 rshift constant MAX_N

Why not like this:
-1 1 rshift constant MAX_N

groet Coos

Anton Ertl

unread,
Apr 25, 2017, 9:45:23 AM4/25/17
to
krishna...@ccreweb.org writes:
>> 1) No hardware implements modulo arithmetic for division (and IIRC
>> that would only be defined for odd divisors anyway), and even if it
>> did, programs would probably usually prefer division-with-remainder.
...
>While rationale 1) is weak

I think you are just missing what "modulo arithmetic for division"
means:

E.g., on a 64-bit system, 1 3 / would result in 12297829382473034411
(because 3*12297829382473034411 gives 1 (mod 2^64)), while 1 2 / has
no result, and 0 2 / has two (0 and 9223372036854775808).

>I suggest documenting these reasons in the appendix.

Your proposal for that is welcome. For a more lightweight approach,
you can add a contribution at forth-standard.org.

Elizabeth D. Rather

unread,
Apr 25, 2017, 2:08:30 PM4/25/17
to
The assumption is that the author of a standard system wants people to
use it, and so will make reasonable choices for "implementation defined"
behaviors. Documentation describing demons is likely to discourage
users. So, it would be legal but counter-productive. And you as a user
are empowered to make rational decisions about the systems you choose to
use.

krishna...@ccreweb.org

unread,
Apr 25, 2017, 6:22:10 PM4/25/17
to
On Tuesday, April 25, 2017 at 8:32:17 AM UTC-5, Coos Haak wrote:
> Op Mon, 24 Apr 2017 18:35:53 -0700 (PDT) schreef
> krishna...@ccreweb.org:
...
> > -1 1 lshift 1 rshift constant MAX_N
>
> Why not like this:
> -1 1 rshift constant MAX_N
> ...

That works too :-)

KM

krishna...@ccreweb.org

unread,
Apr 25, 2017, 6:29:43 PM4/25/17
to
On Tuesday, April 25, 2017 at 8:45:23 AM UTC-5, Anton Ertl wrote:
> krishna...@ccreweb.org writes:
> >> 1) No hardware implements modulo arithmetic for division (and IIRC
> >> that would only be defined for odd divisors anyway), and even if it
> >> did, programs would probably usually prefer division-with-remainder.
> ...
> >While rationale 1) is weak
>
> I think you are just missing what "modulo arithmetic for division"
> means:
> ...

That's not only possible, it's probable!

> >I suggest documenting these reasons in the appendix.
>
> Your proposal for that is welcome. For a more lightweight approach,
> you can add a contribution at forth-standard.org.
>

Ok. Thanks.

Also, with regards to signed and unsigned multiplication overflow, and following up on your earlier suggestions of using words,

: n* ( n1 n2 -- n )
m* >r s>d r> <> -11 and throw ;

: u* ( u1 u2 -- u )
um* 0<> -11 and throw ;

the names should probably be S* , instead of N* , and U* . These can be very efficiently coded on a processor which sets the overflow and/or carry flags for a multiply operation.

Krishna



Anton Ertl

unread,
Apr 26, 2017, 10:56:49 AM4/26/17
to
"Elizabeth D. Rather" <era...@forth.com> writes:
>The assumption is that the author of a standard system wants people to
>use it, and so will make reasonable choices for "implementation defined"
>behaviors. Documentation describing demons is likely to discourage
>users.

The same would be true of nasal demons for undefined behaviour. The
discouragement happens to some extent, but the GCC and Clang
maintainers apparently don't care much about that; they write
promotional material to justify the nasal demons (such as
<http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html>).
Maybe it's part of a crippleware-like business model.
EuroForth 2017: http://www.euroforth.org/ef17/

HAA

unread,
Apr 27, 2017, 12:02:53 AM4/27/17
to
krishna...@ccreweb.org wrote:
> On Tuesday, April 25, 2017 at 7:01:45 AM UTC-5, Anton Ertl wrote:
> ...
> > And if you want to be sure that there is no overflow, you
> > can make sure with M* or UM*.
> >
>
> I'm considering implementing a separate "safe" multiply operator for single length
> operands, which will throw an error on overflow, with an appropriate diagnostic
> message. Clearly, the programmer did not intend for the multiply to overflow, and
> should have the opportunity to be informed of it so that the code can be fixed.
>
> Krishna

The potential for overflow is inherent in computing since it deals with finite resources.
The job of a programmer is to foresee instances where such might be an issue.
Because it is forefront in a programmer's mind, such errors tend not to happen in
my experience. Forth's mixed division operators ought to be very susceptible to
overflow, but again I find they don't happen - even when programming 16-bit systems.
I have an overflow/divzero check in my division primitive but that's only to avoid the
hardware interrupt which would otherwise throw me out of forth. I still let the overflows
happen silently.

The tendency to include 'checking' has, I think, more to do with system providers
wanting to make their system easy for *others* to use, rather than from any personal
need. I contend a user who seriously wishes to program will not remain a novice
for long (assuming they ever were).

Where I do occasionally slip up and appreciate a warning is syntax e.g. forgetting
a THEN because I'd been too busy getting the run-time code right. Early forth
systems had no compile-time checking and programmers still survived. Perhaps
I could too.



krishna...@ccreweb.org

unread,
Apr 27, 2017, 7:00:37 PM4/27/17
to
On Wednesday, April 26, 2017 at 11:02:53 PM UTC-5, HAA wrote:
> krishna...@ccreweb.org wrote:
> > On Tuesday, April 25, 2017 at 7:01:45 AM UTC-5, Anton Ertl wrote:
> > ...
> > > And if you want to be sure that there is no overflow, you
> > > can make sure with M* or UM*.
> > >
> >
> > I'm considering implementing a separate "safe" multiply operator for single length
> > operands, which will throw an error on overflow, with an appropriate diagnostic
> > message. Clearly, the programmer did not intend for the multiply to overflow, and
> > should have the opportunity to be informed of it so that the code can be fixed.
> >
> > Krishna
>
> The potential for overflow is inherent in computing since it deals with finite resources.
> The job of a programmer is to foresee instances where such might be an issue.
> Because it is forefront in a programmer's mind, such errors tend not to happen in
> my experience.

Such errors may be rare, but it only takes one particular application instance to wind up costing a lot of money to fix, when it takes a lot of time to troubleshoot and there are no run-time overflow aborts/messages from the system. It's application dependent as well.

> Forth's mixed division operators ought to be very susceptible to
> overflow, but again I find they don't happen - even when programming 16-bit systems.
> I have an overflow/divzero check in my division primitive but that's only to avoid the
> hardware interrupt which would otherwise throw me out of forth. I still let the overflows
> happen silently.

So you allow div by zero to be handled by returning an incorrect output? This might be ok for certain applications, but not all. I think a better way to do this is to throw an error and provide a warning to the programmer, so he/she can choose for themselves how to handle such a situation. That's a more general approach.

>
> The tendency to include 'checking' has, I think, more to do with system providers
> wanting to make their system easy for *others* to use, rather than from any personal
> need. I contend a user who seriously wishes to program will not remain a novice
> for long (assuming they ever were).
>

My primary user for the system which I implemented is myself. The checking is primarily for my benefit, and for those few to whom I teach programming of my system. I want error checking and useful messages to the programmer to not miss those errors which cannot produce anything except garbage, and therefore result in incorrect output. I'm not talking about compile time warnings of possible overflows on arithmetic -- those would be too numerous and useless. I'm talking about run-time errors which would have only likely have been caught after the fact from looking at the output data. In such cases a run time abort and error message can save considerable time and effort in debugging, and that can amount to a lot of money being saved.

> Where I do occasionally slip up and appreciate a warning is syntax e.g. forgetting
> a THEN because I'd been too busy getting the run-time code right. Early forth
> systems had no compile-time checking and programmers still survived. Perhaps
> I could too.

From the earliest days of my Forth system, I had checks for incomplete flow control structures, with explicit error messages, e.g. for a DO without a matching LOOP, etc. I have found those messages to be enormous time savers. I've been programming for over three decades, in multiple languages/computing environments. Can I debug a program without such explicit feedback? Probably. But it's sure a heck of a lot easier when the system gives me accurate information about compiling and run-time errors.

Krishna


Elizabeth D. Rather

unread,
Apr 28, 2017, 1:20:21 AM4/28/17
to
On 4/27/17 1:00 PM, krishna...@ccreweb.org wrote:
> On Wednesday, April 26, 2017 at 11:02:53 PM UTC-5, HAA wrote:
>> krishna...@ccreweb.org wrote:
>>> On Tuesday, April 25, 2017 at 7:01:45 AM UTC-5, Anton Ertl wrote:
>>> ...
>>>> And if you want to be sure that there is no overflow, you
>>>> can make sure with M* or UM*.
>>>
>>> I'm considering implementing a separate "safe" multiply operator for single length
>>> operands, which will throw an error on overflow, with an appropriate diagnostic
>>> message. Clearly, the programmer did not intend for the multiply to overflow, and
>>> should have the opportunity to be informed of it so that the code can be fixed.
>>
>> The potential for overflow is inherent in computing since it deals with finite resources.
>> The job of a programmer is to foresee instances where such might be an issue.
>> Because it is forefront in a programmer's mind, such errors tend not to happen in
>> my experience.
>
> Such errors may be rare, but it only takes one particular application instance to wind up costing a lot of money to fix, when it takes a lot of time to troubleshoot and there are no run-time overflow aborts/messages from the system. It's application dependent as well.

In my first programming job (before many of you were born) we were
taught to test every subroutine through every possible input value (the
whole number range). It had to tolerate anything.

Later, I learned that when you're working on a Forth application, you
have a lot of information about what input you will get: the A/D has 12
bits, the clock cycles after so many seconds, and user input has to fall
within a specified range. If the hardware is out of range it's broken; a
user who enters a bogus number has to be prompted to correct it. If
error checking is done at the point when bad info can enter the system,
you don't need it at the lower levels.

>> Forth's mixed division operators ought to be very susceptible to
>> overflow, but again I find they don't happen - even when programming 16-bit systems.
>> I have an overflow/divzero check in my division primitive but that's only to avoid the
>> hardware interrupt which would otherwise throw me out of forth. I still let the overflows
>> happen silently.

That's my experience as well.

> So you allow div by zero to be handled by returning an incorrect output? This might be ok for certain applications, but not all. I think a better way to do this is to throw an error and provide a warning to the programmer, so he/she can choose for themselves how to handle such a situation. That's a more general approach.

In development, you need to ensure that all your inputs are validated
and that your code will process the data according to the rules. If
there is a circumstance in which you might have a divide by zero despite
having all legal inputs, you have a logical flaw. That's what needs to
be fixed. If you have ensured that, you don't need to check for a zero
divisor before every division.

>> The tendency to include 'checking' has, I think, more to do with system providers
>> wanting to make their system easy for *others* to use, rather than from any personal
>> need. I contend a user who seriously wishes to program will not remain a novice
>> for long (assuming they ever were).

It's a state of mind.

> My primary user for the system which I implemented is myself. The checking is primarily for my benefit, and for those few to whom I teach programming of my system. I want error checking and useful messages to the programmer to not miss those errors which cannot produce anything except garbage, and therefore result in incorrect output. I'm not talking about compile time warnings of possible overflows on arithmetic -- those would be too numerous and useless. I'm talking about run-time errors which would have only likely have been caught after the fact from looking at the output data. In such cases a run time abort and error message can save considerable time and effort in debugging, and that can amount to a lot of money being saved.
>
>> Where I do occasionally slip up and appreciate a warning is syntax e.g. forgetting
>> a THEN because I'd been too busy getting the run-time code right. Early forth
>> systems had no compile-time checking and programmers still survived. Perhaps
>> I could too.
>
> From the earliest days of my Forth system, I had checks for incomplete flow control structures, with explicit error messages, e.g. for a DO without a matching LOOP, etc. I have found those messages to be enormous time savers. I've been programming for over three decades, in multiple languages/computing environments. Can I debug a program without such explicit feedback? Probably. But it's sure a heck of a lot easier when the system gives me accurate information about compiling and run-time errors.

The easiest way to check for an incomplete structure is just to type .
after compiling anything. If you've left off a structure ending, the
address to be patched will be left on the stack. Easy!

HAA

unread,
Apr 28, 2017, 8:41:43 AM4/28/17
to
Elizabeth D. Rather wrote:
> On 4/27/17 1:00 PM, krishna...@ccreweb.org wrote:
> > On Wednesday, April 26, 2017 at 11:02:53 PM UTC-5, HAA wrote:
> > ...
> >> Where I do occasionally slip up and appreciate a warning is syntax e.g. forgetting
> >> a THEN because I'd been too busy getting the run-time code right. Early forth
> >> systems had no compile-time checking and programmers still survived. Perhaps
> >> I could too.
> >
> > From the earliest days of my Forth system, I had checks for incomplete flow control
> > structures, with explicit error messages, e.g. for a DO without a matching LOOP, etc.
> > I have found those messages to be enormous time savers. I've been programming for
> > over three decades, in multiple languages/computing environments. Can I debug a
> > program without such explicit feedback? Probably. But it's sure a heck of a lot
> > easier when the system gives me accurate information about compiling and run-time
> > errors.
>
> The easiest way to check for an incomplete structure is just to type .
> after compiling anything. If you've left off a structure ending, the
> address to be patched will be left on the stack. Easy!
>
> Cheers,
> Elizabeth

The concern with a completely unsecured compiler is risk of a syntax error
resulting in a corrupted system (Swiss cheese effect). For that reason some
built-in test/verification would seem advisable.



0 new messages