Discussion:
Overflow Test for M*/
(too old to reply)
Krishna Myneni
2024-07-10 11:16:01 UTC
Permalink
Here's a simple check to see what your Forth system does when M*/ is
given arguments which will overflow a double length result. The standard
states that this is an ambiguous condition.

: ipow ( n u -- d ) 1 s>d rot 0 ?DO 2 pick 1 m*/ LOOP rot drop ;

65 21 ipow d.
117809547936177440979200839996337890625 ok \ result ok (64-bit system)

65 22 ipow d.
Floating point exception (core dumped) \ kForth-64 (since last commit)

65 raised to the power of 22 will overflow the double number result on a
64-bit system and crash on kForth-64. Prior to my recent patch it would
overflow silently and print an incorrect result.


In kForth, a SIGFPE handler may be installed as shown in the example
sigfpe.4th.

include sigfpe
\ ...
65 22 ipow d.
Floating point exception
Line 16: VM Error(-258): Return stack corrupt
65 22 ipow d.
ok \ returns to the Forth prompt


To be clear there is no floating point operation involved in IPOW as
defined above, but the exception generated for integer division overflow
for a double length number divided by a single length number generates
SIGFPE on linux.

--
Krishna
minforth
2024-07-10 11:55:18 UTC
Permalink
Good to have a choice. The now standardised big integer
wrap-around behaviour in Forth can indeed cause difficulties.

The other way is to use a small bignum library eg libtommath.
(afaik Python uses fat GMP)

MicroPython v1.19.1 on 2022-11-05; win32 [GCC 6.3.0] version
Use Ctrl-D to exit, Ctrl-E for paste mode
pow(65,21)
117809547936177440979200839996337890625
pow(65,22)
7657620615851533663648054599761962890625
Krishna Myneni
2024-07-10 12:31:23 UTC
Permalink
Post by minforth
Good to have a choice. The now standardised big integer
wrap-around behaviour in Forth can indeed cause difficulties.
The Forth 2012 standard for M*/ states an ambiguous condition for a
quotient outside of the range of a double-precision signed number:

8.6.1.1820

M*/ ( d1 n1 +n2 – – d2 )
Multiply d1 by n1 producing the triple-cell intermediate result t.
Divide t by +n2 givingthe 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.

--
Krishna
minforth
2024-07-12 19:29:52 UTC
Permalink
Why n2 has to be positive is beyond me anyhow.
dxf
2024-07-13 02:03:54 UTC
Permalink
Post by minforth
Why n2 has to be positive is beyond me anyhow.
The TC offered an explanation for that one:

A.8.6.1.1820 M*/

[...] Note that some systems allow signed divisors. This can cost a lot in performance
on some CPUs. The requirement for a positive divisor has not proven to be a problem.

How many applications have you written requiring a negative divisor?
mhx
2024-07-13 07:15:34 UTC
Permalink
On Sat, 13 Jul 2024 2:03:54 +0000, dxf wrote:

[..]
Post by dxf
How many applications have you written requiring a negative divisor?
I note that in the 68 occurrences of M*/ inside about 1900 files,
32 appear as ".. 1 M*/ ..".

-marcel
Krishna Myneni
2024-07-13 12:18:11 UTC
Permalink
Post by mhx
[..]
Post by dxf
How many applications have you written requiring a negative divisor?
I note that in the 68 occurrences of M*/ inside about 1900 files,
32 appear as ".. 1 M*/ ..".
The use of 1 M*/ just points to a missing factor of M*/ being omitted
from the standard. In kForth, we provide the missing factor:

DS* ( d n -- t )

where t is a signed triple length product. Therefore, 1 M*/ can be
replaced by

DS* drop

and the division can be avoided.

If you need an overflow check, it may be a bit more complicated, though.

--
Krishna
dxf
2024-07-14 03:59:20 UTC
Permalink
Post by Krishna Myneni
Post by mhx
[..]
Post by dxf
How many applications have you written requiring a negative divisor?
I note that in the 68 occurrences of M*/ inside about 1900 files,
32 appear as ".. 1 M*/ ..".
DS* ( d n -- t )
where t is a signed triple length product. Therefore, 1 M*/ can be replaced by
DS* drop
and the division can be avoided.
If you need an overflow check, it may be a bit more complicated, though.
Conversely one might factor >NUMBER :

: MU* ( ud1 u -- ud2 ) tuck * >r um* r> + ;

So far I've not needed a signed version...

minforth
2024-07-13 08:15:26 UTC
Permalink
Post by dxf
How many applications have you written requiring a negative divisor?
What a silly question.

Even in simple Newtonian physics it is not always possible to define
a reference system that avoids negative values. Let alone in
electrical networks.

The "explanation" that +n2 is there to compensate for the performance
loss of some (old?) CPUs sounds strange in a standard document.
mhx
2024-07-13 09:03:40 UTC
Permalink
Post by minforth
Even in simple Newtonian physics it is not always possible to define
a reference system that avoids negative values. Let alone in
electrical networks.
I have never felt the need to use M*/ when solving electrical
networks. Maybe when I finally get to Katzenelson.

-marcel
dxf
2024-07-13 09:42:16 UTC
Permalink
Post by minforth
Post by dxf
How many applications have you written requiring a negative divisor?
What a silly question.
Even in simple Newtonian physics it is not always possible to define
a reference system that avoids negative values. Let alone in
electrical networks.
Moore defined floored division which used only positive/unsigned divisors.
So I was curious.
Post by minforth
The "explanation" that +n2 is there to compensate for the performance
loss of some (old?) CPUs sounds strange in a standard document.
Can you make the case it shouldn't? Truth cares nothing for what may,
or may not, exist in a Forth Standard.
Loading...