feat(v4.0.0): SM/REM and DNEGATE call-free; execute /MOD and its section 5 words
SM/REM as written in section 4 never returned correctly for a negative dividend. It holds three entries on the return stack and then calls DABS -> DNEGATE -> D+ -> U> -> SWAP/U<, which overflows the 9-deep circular return stack (D-2). DABS itself could not run: DNEGATE as written (inv SWAP inv SWAP 1 0 D+) left its caller no return entries. - DNEGATE: inv over if L1 drop push inv 1 + pop ; L1: drop 1 + ; i.e. ~d + 1, carrying into the high cell exactly when lo = 0. - SM/REM: sign tests are native -if (as in 0<) and NEGATE is in line; the only calls are DNEGATE and UM/MOD, both call-free inside. Executed on the golden model at 32- and 64-bit cells, optimised and under ASan+UBSan: - SM/REM on dividends built as q*n + r with |r| < |n| and r signed as d: every edge-vector q, n with r = 0 and r = +-(|n|-1), plus 20000 pseudo-random cases. - /MOD, U>, ABS, S>D, D+ and DABS as written in section 5, against C (D+ over all 50625 edge-vector quadruples). Mutations of DNEGATE's carry and of each SM/REM sign branch are caught. Headroom (data cells under args / return entries under return address): SM/REM 5/3, /MOD 5/2, DNEGATE 7/7, DABS 7/6, ABS 8/7, U> 6/5. D+ as written is exact but leaves only 1 return entry; recorded in DECOMPOSITION.md 5.7 as not yet revised. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
3b9d1e4337
commit
93d09840da
@@ -256,15 +256,27 @@ dependency order.
|
||||
\ times as many instruction words.
|
||||
|
||||
\ ---- signed division, truncating toward zero (v3 semantics) -------------
|
||||
\ The quotient takes the sign of d xor n, the remainder the sign of d. Sign
|
||||
\ tests are native -if (as in 0<) and NEGATE is in line, so the only calls
|
||||
\ are DNEGATE and UM/MOD, both call-free inside.
|
||||
: SM/REM ( d n -- rem quot )
|
||||
2DUP xor push \ R: quotient sign
|
||||
over push \ R: remainder sign (sign of dividend)
|
||||
ABS push DABS pop UM/MOD
|
||||
pop 0< IF push NEGATE pop THEN
|
||||
pop 0< IF NEGATE THEN ;
|
||||
over over xor push \ R: quotient sign (top bit)
|
||||
over push \ R: + remainder sign (top bit of d)
|
||||
-if L0 inv 1 + L0: push \ R: + |n|
|
||||
-if L1 DNEGATE L1: \ |d|
|
||||
pop UM/MOD \ urem uquot
|
||||
pop -if L2 drop push inv 1 + pop jump L3 L2: drop L3:
|
||||
pop -if L4 drop inv 1 + ; L4: drop ;
|
||||
\ Executed on the golden model (2026-10-02): exact whenever the truncated
|
||||
\ quotient fits a signed cell, at 32- and 64-bit cells. Stack use (D-2): up
|
||||
\ to 5 data cells under the three arguments and 3 return-stack entries under
|
||||
\ its return address; /MOD, one call further out, leaves 2. The first
|
||||
\ version, built on ABS, DABS, 0< and NEGATE calls, overflowed the return
|
||||
\ stack inside DABS -> DNEGATE -> D+ -> U> and never returned correctly for
|
||||
\ a negative dividend.
|
||||
```
|
||||
|
||||
`2DUP`, `-`, `ABS`, and `DABS` are defined in §5; the compiler resolves forward references within the
|
||||
`2DUP`, `-`, and `DNEGATE` are defined in §5; the compiler resolves forward references within the
|
||||
core capsule.
|
||||
|
||||
---
|
||||
@@ -341,7 +353,7 @@ Section numbers match the v3 primitive reference.
|
||||
| `1+` `1-` `2+` `2-` | IN | `1 +`, `-1 +`, `2 +`, `-2 +` |
|
||||
| `2*` | OP | `2*` |
|
||||
| `2/` | OP | `2/` |
|
||||
| `ABS` | CAP | `dup 0< IF NEGATE THEN` |
|
||||
| `ABS` | CAP | `dup 0< IF NEGATE THEN` — executed on the golden model (2026-10-02). |
|
||||
| `NEGATE` | CAP | §4 |
|
||||
| `MIN` | CAP | `2DUP > IF SWAP THEN drop` |
|
||||
| `MAX` | CAP | `2DUP < IF SWAP THEN drop` |
|
||||
@@ -367,7 +379,7 @@ Section numbers match the v3 primitive reference.
|
||||
| `<=` | CAP | `> 0=` |
|
||||
| `>=` | CAP | `< 0=` |
|
||||
| `U<` | CAP | §4 |
|
||||
| `U>` | CAP | `SWAP U<` |
|
||||
| `U>` | CAP | `SWAP U<` — executed on the golden model (2026-10-02). |
|
||||
| `WITHIN` | CAP | `over - push - pop U<` |
|
||||
| `TRUE` | IN | `-1` |
|
||||
| `FALSE` | IN | `0` |
|
||||
@@ -383,7 +395,7 @@ A double is two 32-bit cells on a mesh node.
|
||||
| `M*` | CAP | `2DUP xor push ABS SWAP ABS UM* pop 0< IF DNEGATE THEN` |
|
||||
| `M/MOD` | CAP | `SM/REM` |
|
||||
| `MOD` | CAP | `/MOD drop` |
|
||||
| `/MOD` | CAP | `push S>D pop SM/REM` |
|
||||
| `/MOD` | CAP | `push S>D pop SM/REM` — executed on the golden model (2026-10-02). |
|
||||
| `*/` | CAP | `*/MOD NIP` |
|
||||
| `*/MOD` | CAP | `push M* pop SM/REM` |
|
||||
|
||||
@@ -391,11 +403,11 @@ A double is two 32-bit cells on a mesh node.
|
||||
|
||||
| Word | Fate | v4 definition |
|
||||
| --- | --- | --- |
|
||||
| `S>D` | CAP | `dup 0<` |
|
||||
| `D+` | CAP | `push SWAP push over + 2DUP U> ROT drop NEGATE pop pop + +` |
|
||||
| `DNEGATE` | CAP | `inv SWAP inv SWAP 1 0 D+` |
|
||||
| `S>D` | CAP | `dup 0<` — executed on the golden model (2026-10-02). |
|
||||
| `D+` | CAP | `push SWAP push over + 2DUP U> ROT drop NEGATE pop pop + +` — executed on the golden model and exact (2026-10-02), but leaves its caller only **1** return-stack entry (D-2): anything that calls a word that calls `D+` overwrites a return address. Not yet revised. |
|
||||
| `DNEGATE` | CAP | `inv over if L1 drop push inv 1 + pop ; L1: drop 1 + ;` — call-free: `~d + 1`, carrying into the high cell exactly when the low cell is 0. Executed on the golden model (2026-10-02). Replaces `inv SWAP inv SWAP 1 0 D+`, which left a caller no return-stack room, so `DABS` could not run at all. |
|
||||
| `D-` | CAP | `DNEGATE D+` |
|
||||
| `DABS` | CAP | `dup 0< IF DNEGATE THEN` |
|
||||
| `DABS` | CAP | `dup 0< IF DNEGATE THEN` — executed on the golden model (2026-10-02). |
|
||||
| `D0=` | CAP | `OR 0=` |
|
||||
| `D0<` | CAP | `NIP 0<` |
|
||||
| `D=` | CAP | `D- D0=` |
|
||||
|
||||
Reference in New Issue
Block a user