test(v4.0.0): execute Q.+ and Q.- against v3 Q48.16
DECOMPOSITION.md 5.26 makes Q.+ and Q.- the D+ and D- words. They are checked against v3's q48_add/q48_sub (uint64_t a + b, a - b, wrapping) on every pair of 15 edge Q values (0, ulp, 0.5, 1.0, 1.5, -1.0, -ulp, values across the 32-bit seam, Q max and min, +-12345.0) and 20000 pseudo-random pairs, 2682 of which overflow Q48.16. - 32-bit cells: bit-for-bit v3's result, overflow wrap included. - 64-bit cells, with a Q value as a sign-extended double: the low cell is v3's result; on overflow the high cell holds the true carry where v3 wraps. Whether a Q value is one cell or two on a 64-bit node is not ruled; recorded as open in 5.26. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6a371b850e
commit
5ac52f19d6
@@ -644,7 +644,7 @@ word. Per D-8, v4 Q values are signed.
|
|||||||
|
|
||||||
| Word | Fate | Notes |
|
| Word | Fate | Notes |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `Q.+` `Q.-` | CAP | `D+`, `D-` |
|
| `Q.+` `Q.-` | CAP | `D+`, `D-` — executed on the golden model (2026-10-02) against v3's `q48_add`/`q48_sub` (`uint64_t` wrapping). At 32-bit cells the result is bit-for-bit v3's, overflow included. **Open:** at 64-bit cells a Q value as a sign-extended double has the same low cell as v3, but on Q48.16 overflow the high cell holds the true carry where v3 wraps. Whether a Q value is one cell or two on a 64-bit node is not yet ruled. |
|
||||||
| `Q.*` | CAP | 64×64 product from four `UM*` partial products, shifted right 16. |
|
| `Q.*` | CAP | 64×64 product from four `UM*` partial products, shifted right 16. |
|
||||||
| `Q./` | CAP | Shifted long division. **Division by zero sets an error** (v3 returned 0 silently). |
|
| `Q./` | CAP | Shifted long division. **Division by zero sets an error** (v3 returned 0 silently). |
|
||||||
| `Q.ABS` `Q.NEG` | CAP | `DABS`, `DNEGATE` |
|
| `Q.ABS` `Q.NEG` | CAP | `DABS`, `DNEGATE` |
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "v4/asm.h"
|
#include "v4/asm.h"
|
||||||
#include "v4/testcode.h"
|
#include "v4/testcode.h"
|
||||||
#include "v4/umul.h"
|
#include "v4/umul.h"
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
static int failures = 0, checks = 0;
|
static int failures = 0, checks = 0;
|
||||||
@@ -455,6 +456,46 @@ static int smrem_exact(v4_cell q, v4_cell nn, v4_cell r)
|
|||||||
return call(w_smrem, 3, (v4_cell)dl, (v4_cell)dh, nn) && left2(r, q);
|
return call(w_smrem, 3, (v4_cell)dl, (v4_cell)dh, nn) && left2(r, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Q48.16 (section 5.26). v3's Q.+ and Q.- are uint64_t a + b and a - b,
|
||||||
|
* wrapping (v3/include/q48_16.h). Here a Q value is a double: at 32-bit
|
||||||
|
* cells its two halves, at 64-bit cells the value sign-extended (D-8). */
|
||||||
|
static void qcells(uint64_t q, v4_cell *lo, v4_cell *hi)
|
||||||
|
{
|
||||||
|
#if V4_CELL_BITS == 32
|
||||||
|
*lo = (v4_cell)(v4_ucell)(q & 0xFFFFFFFFu);
|
||||||
|
*hi = (v4_cell)(v4_ucell)(q >> 32);
|
||||||
|
#else
|
||||||
|
*lo = (v4_cell)(v4_ucell)q;
|
||||||
|
*hi = (q >> 63) ? V4_ALL_ONES : 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run Q.+ (the D+ word) or Q.- (the D- word) on a and b and compare with
|
||||||
|
* v3's 64-bit wrapping result. At 32-bit cells the double must equal v3's
|
||||||
|
* value bit for bit. At 64-bit cells the low cell must equal v3's value and
|
||||||
|
* the high cell must be the true sign of the unwrapped result. */
|
||||||
|
static int q_matches_v3(v4_cell word, uint64_t a, uint64_t b, uint64_t v3)
|
||||||
|
{
|
||||||
|
v4_cell al, ah, bl, bh, rl, rh;
|
||||||
|
qcells(a, &al, &ah);
|
||||||
|
qcells(b, &bl, &bh);
|
||||||
|
if (!call4(word, al, ah, bl, bh)) return 0;
|
||||||
|
#if V4_CELL_BITS == 32
|
||||||
|
qcells(v3, &rl, &rh);
|
||||||
|
return left2(rl, rh);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
v4_ucell xl, xh, nl, nh;
|
||||||
|
if (word == w_dminus) { dneg((v4_ucell)bl, (v4_ucell)bh, &nl, &nh); }
|
||||||
|
else { nl = (v4_ucell)bl; nh = (v4_ucell)bh; }
|
||||||
|
dadd((v4_ucell)al, (v4_ucell)ah, nl, nh, &xl, &xh);
|
||||||
|
rl = (v4_cell)(v4_ucell)v3;
|
||||||
|
rh = (v4_cell)xh;
|
||||||
|
return (v4_ucell)rl == xl && left2(rl, rh);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Stack headroom. Run `word` with `dfill` marked cells under the canary and
|
/* Stack headroom. Run `word` with `dfill` marked cells under the canary and
|
||||||
* `rfill` marked cells under its return address, and report whether the
|
* `rfill` marked cells under its return address, and report whether the
|
||||||
* results, the canary and every marked cell come back intact. The F18 stacks
|
* results, the canary and every marked cell come back intact. The F18 stacks
|
||||||
@@ -725,6 +766,37 @@ int main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Q.+ and Q.- (section 5.26: the D+ and D- words) against v3. */
|
||||||
|
{
|
||||||
|
static const uint64_t qv[] = {
|
||||||
|
0, 1, 0x8000u, 0x10000u, 0x18000u, /* 0, ulp, 0.5, 1.0, 1.5 */
|
||||||
|
(uint64_t)0 - 0x10000u, (uint64_t)0 - 1u, /* -1.0, -ulp */
|
||||||
|
0xFFFFu, 0x10001u, 0xFFFFFFFFu, 0x100000000u, /* across the 32-bit seam */
|
||||||
|
((uint64_t)1 << 63) - 1u, (uint64_t)1 << 63, /* Q max, Q min */
|
||||||
|
(uint64_t)12345 << 16, (uint64_t)0 - ((uint64_t)12345 << 16)
|
||||||
|
};
|
||||||
|
const unsigned nq = sizeof qv / sizeof qv[0];
|
||||||
|
uint64_t x = 0x9E3779B97F4A7C15u;
|
||||||
|
unsigned over = 0;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < nq; i++)
|
||||||
|
for (unsigned j = 0; j < nq; j++) {
|
||||||
|
CHECK(q_matches_v3(w_dplus, qv[i], qv[j], qv[i] + qv[j]), "Q.+ [%u,%u]", i, j);
|
||||||
|
CHECK(q_matches_v3(w_dminus, qv[i], qv[j], qv[i] - qv[j]), "Q.- [%u,%u]", i, j);
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < 20000; i++) {
|
||||||
|
uint64_t a, b;
|
||||||
|
x ^= x << 13; x ^= x >> 7; x ^= x << 17; a = x;
|
||||||
|
x ^= x << 13; x ^= x >> 7; x ^= x << 17; b = x;
|
||||||
|
if (i & 1u) a >>= (unsigned)(x & 63u); /* mixed magnitudes */
|
||||||
|
if (i & 2u) b = (uint64_t)0 - b;
|
||||||
|
if (((a + b) ^ a) & ((a + b) ^ b) & ((uint64_t)1 << 63)) over++;
|
||||||
|
CHECK(q_matches_v3(w_dplus, a, b, a + b), "Q.+ random [%u]", i);
|
||||||
|
CHECK(q_matches_v3(w_dminus, a, b, a - b), "Q.- random [%u]", i);
|
||||||
|
}
|
||||||
|
printf(" Q.+ random cases that overflow Q48.16: %u of 20000\n", over);
|
||||||
|
}
|
||||||
|
|
||||||
/* Stack headroom of the two longest definitions. */
|
/* Stack headroom of the two longest definitions. */
|
||||||
{
|
{
|
||||||
static const v4_cell umstar_args[][4] = {
|
static const v4_cell umstar_args[][4] = {
|
||||||
|
|||||||
Reference in New Issue
Block a user