Page 2 of 2

Re: Common D< Forth bug

Posted: Fri Sep 19, 2014 4:34 am
by edx
barrym95838 wrote:
edx wrote:
... particularly when there is D< to handle the exceptional cases.
But that was Garth's original beef. D< DIDN'T handle the exceptional cases for him, and he had to re-write the primitive.
I can only go by comments made here which suggests the 'bug fix' was driven by expectations rather than practical necessity ...
Quote:
Any way you look at it, for D< to say that -70007FFF was not less than 0FFF8002 in signed 32-bit numbers is just plain wrong.
...
D< is not used that much

Re: Common D< Forth bug

Posted: Fri Sep 19, 2014 5:38 am
by GARTHWILSON
edx wrote:
I can only go by comments made here which suggests the 'bug fix' was driven by expectations rather than practical necessity ...
It did come up in a project, the automated test equipment, but I don't remember the exact context within the project. I had to debug a routine, and it turned out there was nothing wrong with my routine but in the D< that was supplied.

Re: Common D< Forth bug

Posted: Fri Sep 19, 2014 7:47 am
by BigEd
I'm tending to agree with the idea that D< does work OK, according to the documentation, but it's an odd spec. It's not signed double size arithmetic, it's something else that's double-sized. Something which is in fact convenient and useful for some applications (timers) and is fine for numerical computation so long as the inputs are relatively close. Garth's failing case has inputs which are very distant.

It would be better for most of us, probably, if the spec had been more straightforward, and the arithmetic was signed double size. Perhaps T< would be a better name (T for timer)

Cheers
Ed

Re: Common D< Forth bug

Posted: Fri Sep 19, 2014 8:49 am
by GARTHWILSON
Or... they could just make it work right for all signed double-number pairs, as its name suggests. That would be easier than explaining what the conditions are under which you shouldn't use it. :D

Re: Common D< Forth bug

Posted: Fri Sep 19, 2014 9:02 am
by BigEd
If it's right for double sized signed arithmetic, then surely it would be wrong for timer arithmetic?

Re: Common D< Forth bug

Posted: Fri Sep 19, 2014 9:53 am
by GARTHWILSON
That's a bit different. What I do with timers, and have done many, many times in multitasking in microcontroller projects to see if it's time for something, is to take the current timer value and subtract the target time calculated earlier, and if the result is negative (ie, high bit set), know that we're not there yet. If it's clear, it's time to do it. So if the current timer value (which might be in arbitrary increments of for example 6ms) is 7F12, target values of 7F13 and 8002 and EFF0 would all yield a negative result, meaning we're not there yet. Enough bits are used such that it will always get checked at less than half way around the circle, so it can't be fooled. It works regardless of what part of the circle you're in. The last project kept four bytes, but depending on what a particular part of the program needed, only bytes 0 and 1 would be used, or only 1 and 2, or oly 2 and 3.

Re: Common D< Forth bug

Posted: Fri Sep 19, 2014 10:12 am
by BigEd
Sounds like you've adopted the same clock-based arithmetic that D< gives you...

Re: Common D< Forth bug

Posted: Fri Jan 03, 2020 6:22 pm
by SamCoVT
GARTHWILSON wrote:
I redefined it in 6502 Forth as:

Code: Select all

: D<  ROT
      2DUP =
      IF 2DROP U< EXIT THEN
      > -ROT 2DROP  ;
I hope it's OK to bring up an old thread, but I'm super happy to see your version of D< as I just got done writing it myself and I wasn't completely certain I had it correct. Mine looks like:

Code: Select all

: D<   ( d1 d2 -- flag )  ( flag is true iff d1 < d2 )
  rot 2dup =  if 2drop u<  else 2swap 2drop > then ;
They end a little differently, but I think they do the same thing. It looks like your version is slightly better in terms of jumping and stack thrashing. I can now see that it's good practice to perform any operations that reduce the stack size before operations that shuffle the stack, when possible.

Re: Common D< Forth bug

Posted: Thu Jun 04, 2020 1:04 am
by JimBoyd
barrym95838 wrote:
To me, it's not a matter of modern vs. vintage, but more of a matter of correct vs. incorrect. The 6502's overflow flag worked correctly for signed binary from its inception ... it was up to the programmer to make proper use of it. In the case of Forth, I believe that access to the overflow flag was limited for application programs, so that duty should have fallen on the person writing the primitives.
That's an interesting idea. I suppose if someone wanted to implement < and D< as high level and keep them as fast as possible, one wild idea would be to write the subtraction primitives ( - and D- ) so that if there was an overflow they would store -1 in a variable named OVERFLOW and store a zero in it otherwise. Better yet, use a VALUE or soft constant. The high level D< could then be:

Code: Select all

: D<   D- D0< OVERFLOW XOR ;
I've never tried this so I don't know if the overall size would be smaller. It just seems simpler to have < and D< as primitives that test the processors overflow flag.
Quote:
The discussion in Section 2.2.2 makes clever use of the phrases "handles the vast majority" and "is generally safe", so I guess it boiled down to a matter of efficiency vs. exhaustive correctness. I have little doubt that a non-zero percentage of modern software hides similar trade-offs, documented or not.

Mike
Section 2.2.2 also states that different behaviour can be expected from different versions of polyforth.
Quote:
16 bit versions of polyFORTH ISD-4 use the fully signed model (option “a” in Fig. 2.1) to implement most
relationals, as well as MAX and MIN. 32-bit versions of polyFORTH use the circular model.