Finding inverse operation to George Marsaglia's XorShift RNG - algorithm

Abstract
Hi, suppose you have 128 bit automata (represented by four 32 bit words X, Y, Z, W) that changes it's state according to a following rule:
X = ...
Y = ...
Z = ...
W = ...
void next()
{
var t = X ^ (X << 11);
X = Y;
Y = Z;
Z = W;
W = W ^ (W >> 19) ^ (t ^ (t >> 8));
}
^ - denotes binary XOR operation
<< - denotes binary shift left operation
>> - denotys binary shift right operation
It is guaranteed that the above automata generates no collisions i.e. each state is a result of one (and only one) previous state. It is also guaranteed that the above state machine produces 2^128 unique states.
Question
For any given state (X,Y,Z,W) produce inverse to next, (i.e. prev) operation that would revert the state to previous one.
In other words, if you have the following state (X=1, Y=2, Z=3, W=4) and will call next, the state will change to (X=2, Y=3, Z=4, W=2061), it is supposed that after calling prev the state should be equal again to (X=1, Y=2, Z=3, W=4).
P.S.
The next operation is one of the implementations to XorShift pseudorandom number generators that was discovered by George Marsaglia
https://en.wikipedia.org/wiki/Xorshift
The inverse to this operation would be very useful in general, consider the implications of Guid.Next(...), Guid.Prev(...) availability
Edit
I have somewhat improved Niklas B.'s original answer and ported result to C#, so here's the final piece of code, hope someone will benefit from Random.Next() and Random.Prev() operations:
public class Xor128
{
public UInt32 X { get; set; }
public UInt32 Y { get; set; }
public UInt32 Z { get; set; }
public UInt32 W { get; set; }
public Xor128()
{
}
public Xor128(UInt32 x, UInt32 y, UInt32 z, UInt32 w)
{
X = x;
Y = y;
Z = z;
W = w;
}
//private UInt32 UnXorShl(UInt32 x, Int32 shift)
//{
// for (var i = shift; i < 32; i <<= 1) {
// x ^= x << i;
// }
// return x;
//}
//private UInt32 UnXorShr(UInt32 x, Int32 shift)
//{
// for (var i = shift; i < 32; i <<= 1) {
// x ^= x >> i;
// }
// return x;
//}
//public UInt32 Prev()
//{
// var t = UnXorShr(W ^ Z ^ (Z >> 19), 8);
// W = Z;
// Z = Y;
// Y = X;
// X = UnXorShl(t, 11);
// return W;
//}
public UInt32 Prev()
{
var t = W ^ Z ^ (Z >> 19);
t ^= t >> 8;
t ^= t >> 16;
W = Z;
Z = Y;
Y = X;
t ^= t << 11;
t ^= t << 22;
X = t;
return W;
}
public UInt32 Curr()
{
return W;
}
public UInt32 Next()
{
UInt32 t = X ^ (X << 11);
X = Y;
Y = Z;
Z = W;
return W = W ^ (W >> 19) ^ (t ^ (t >> 8));
}
}
btw. Here's a swift version:
public class Xor128 {
public var X: UInt32
public var Y: UInt32
public var Z: UInt32
public var W: UInt32
public convenience init(uuid: uuid_t) {
let xa = (UInt32(uuid.0 ) << 24)
let xb = (UInt32(uuid.1 ) << 16)
let xc = (UInt32(uuid.2 ) << 8 )
let xd = (UInt32(uuid.3 ) << 0 )
let ya = (UInt32(uuid.4 ) << 24)
let yb = (UInt32(uuid.5 ) << 16)
let yc = (UInt32(uuid.6 ) << 8 )
let yd = (UInt32(uuid.7 ) << 0 )
let za = (UInt32(uuid.8 ) << 24)
let zb = (UInt32(uuid.9 ) << 16)
let zc = (UInt32(uuid.10) << 8 )
let zd = (UInt32(uuid.11) << 0 )
let wa = (UInt32(uuid.12) << 24)
let wb = (UInt32(uuid.13) << 16)
let wc = (UInt32(uuid.14) << 8 )
let wd = (UInt32(uuid.15) << 0)
self.init(
x: xa + xb + xc + xd,
y: ya + yb + yc + yd,
z: za + zb + zc + zd,
w: wa + wb + wc + wd
)
}
public convenience init(uuid: UUID) {
self.init(uuid: uuid.uuid)
}
public init(x: UInt32, y: UInt32, z: uint32, w: UInt32) {
X = x
Y = y
Z = z
W = w
}
#discardableResult
public func next() -> UInt32 {
let t = X ^ (X << 11);
X = Y;
Y = Z;
Z = W;
W = W ^ (W >> 19) ^ (t ^ (t >> 8))
return W;
}
public var curr: UInt32 {
return W
}
#discardableResult
public func prev() -> UInt32 {
var t = W ^ Z ^ (Z >> 19);
t ^= t >> 8;
t ^= t >> 16;
W = Z;
Z = Y;
Y = X;
t ^= t << 11;
t ^= t << 22;
X = t;
return W;
}
}

The basic building block you need is an algorithm to reverse the XOR with left shift operation f(x) = x ^ (x << s) for some s > 0. Given f(x), you already know the lower s bits of x directly.
You can reconstruct the rest of the bits iteratively from low to high, because you already know at each point the two bits that have been XORed to get the bit of f(x). Here's an example in Python:
def reverse_xor_lshift(y, shift, w=32):
x = y & ((1<<shift) - 1)
for i in range(w - shift):
x |= (1 if bool(x & (1<<i)) ^ bool(y & (1<<(shift+i))) else 0)<<(shift+i)
return x
Now the rest becomes rather easy. Note that I'm reusing the left shift reversal for the right shift analogue:
def reverse_bin(x, w=32):
return int(bin(x)[2:].rjust(w, '0')[::-1], 2)
def reverse_xor_rshift(y, shift, w=32):
# for simplicity, we just reuse reverse_xor_lshift here
return reverse_bin(reverse_xor_lshift(reverse_bin(y), shift))
def forward(X, Y, Z, W):
t = (X ^ (X << 11)) & 0xffffffff
X = Y
Y = Z
Z = W
W = W ^ (W >> 19) ^ (t ^ (t >> 8))
return (X, Y, Z, W)
def backward(X, Y, Z, W):
t = reverse_xor_rshift(W ^ Z ^ (Z >> 19), 8)
return (reverse_xor_lshift(t, 11), X, Y, Z)
backward is the function that reverses the state transition. Some random testing:
import random
for _ in range(1000):
X, Y, Z, W = [random.randint(0,2**32-1) for _ in range(4)]
assert backward(*forward(X,Y,Z,W)) == (X, Y, Z, W)
Seems to work.

For Y, Z and W, we can easily reverse it. For X, we need to make some observations:
W' = W ^ (W >> 19) ^ (t ^ (t >> 8)), -> t ^ (t >> 8) = W' ^ (W ^ (W >> 19))
So, now, we have t ^ (t >> 8) = W' ^ (W ^ (W >> 19)) = a
t = X ^ (X << 11)
-> t ^ (t >> 8) = X ^ (X << 11) ^ ((X ^ (X <<11)) >> 8)
= X ^ (X << 11) ^ (X >> 8) ^ (X << 3)
Denoting each bit of X as x0, x1, x2, ... x31, and each bit of a as a0, a1, ... we can form following equation system:
x0 ^ x8 = a0
x1 ^ x9 = a1
.....
Or, equivalent to:
(x0 + x8) % 2 = a0
(x1 + x9) % 2 = a1
....
Which we can easily solve by applying Gaussian elimination.

Related

Diamond-Square algorithm gives a heightMap with square lines and a lot of black space

I'm working on implementation of the Diamond-square algorithm but the outcoming heightmap looks strange like some points are not filled:
I've tried to change for stateents but I still can't find where these points can be missed. Here is my code of a function which is filling the one-dimensional heightMap of values between 0.0 and 1.0.
func diamond(x1 int, y1 int, x2 int, y2 int, l int, size int, r float32) {
var a, b, c, d float32
var cx, cy int
a = heightMap[x1 + y1*size]
b = heightMap[x1 + y2*size]
c = heightMap[x2 + y2*size]
d = heightMap[x2 + y1*size]
cx = (x2 - x1)/2
cy = (y2 - y1)/2
heightMap[cx + cy*size] = float32(a + b + c + d)/float32(4) + rand.Float32()*r
}
func square(cx int, cy int, l int, size int, r float32) {
var a, b, c, d float32
var isBorder = float32(0)
if cx == 0 {
isBorder = 1
a = 0
} else {
a = heightMap[cx - l/2 + cy*size]
}
if cy == size - 1 {
isBorder = 1
b = 0
} else {
b = heightMap[cx + (cy + l/2)*size]
}
if cx == size - 1 {
isBorder = 1
c = 0
} else {
c = heightMap[cx + l/2 + cy*size]
}
if cy == 0 {
isBorder = 1
d = 0
} else {
d = heightMap[cx + (cy - l/2)*size]
}
heightMap[cx + cy*size] = float32(a + b + c + d)/float32(4 - isBorder) + rand.Float32()*r
}
func initHeightMap(size int) {
rand.Seed(3256)
heightMap = make([]float32, size*size)
heightMap[0] = rand.Float32()
heightMap[size-1] = rand.Float32()
heightMap[(size-1)*size] = rand.Float32()
heightMap[size*size-1] = rand.Float32()
var t int
t = size - 1
for l := size - 1; l > 0; l /= 2 {
//diamond steps
for y := 0; y < size - 1; y += l {
for x := 0; x < size - 1; x += l {
diamond(x, y, x + l, y + l, l, size, float32(l)/float32(size-1))
}
}
//square steps
if l > 1 {
for y := 0; y < size - 1; y += l/2 {
if t%2 == 0 {
for x := l/2; x < size; x += l {
square(x, y, l, size, float32(l)/float32(size-1))
}
} else {
for x := 0; x < size; x += l {
square(x, y, l, size, float32(l)/float32(size-1))
}
}
t++
}
}
}
}
Size is a value which is always a power of 2 plus 1 and a random number range is halfed with l.
I've seen a similar heightmap in this question Unexpected Diamond square Algorithm results but there was a different mistake in the algorithm.

evenBitParity - returns 1 if an odd number of the even-indexed bits of x are 0's (bit 0 of x is the 1's place)

The is a bit manipulation problem.
/*
evenBitParity - returns 1 if an odd number of the even-indexed bits of x are 0's (bit 0 of x is the 1's place)
Examples:
evenBitParity(0) = 0 (16 zero even-indexed bits),
evenBitParity(2) = 0 (16 zero even-indexed bits, bit 1 is non-zero but not even-indexed)
evenBitParity(3) = 1 (15 zero even-indexed bits),
evenBitParity(5) = 0 (14 zero-indexed bits),
evenBitParity(7) = 0
evenbitParity(21) = 1
Legal ops: ! ~ & ^ | + << >>
Max ops: 15
Rating: 4
*/
int evenBitParity(int x) {
}
I try to solve it with the code below, but the operations are too many so I didn't get full credit. Can anyone give a better solution for this?
Thanks a lot!
int masker = (0x55 << 8)+0x55;
masker = (masker<<16)+masker;
x = x&masker;
x = x ^ (x >> 1);
x = x ^ (x >> 2);
x = x ^ (x >> 4);
x = x ^ (x >> 8);
x = x ^ (x >> 16);
return x&1;
A better solution:
int masker = (0x55 << 8)+0x55;
y = (x >> 16) & masker;
x = x&masker;
x = x ^ y;
x = x ^ (x >> 1);
x = x ^ (x >> 2);
x = x ^ (x >> 4);
x = x ^ (x >> 8);
return x&1;
Try this one for your self. The improved version is ebp2();
You didn't need to use a mask and all that. Simply omit the first shift to ignore all odd-indexed bits.
I think I deserve a beer or at least a coffee for my effort.
int main(int argc, char** argv){
int x;
x = 0;
printf("%d\t%d\t%d\n", x, ebp1(x), ebp2(x));
x = 2;
printf("%d\t%d\t%d\n", x, ebp1(x), ebp2(x));
x = 3;
printf("%d\t%d\t%d\n", x, ebp1(x), ebp2(x));
x = 5;
printf("%d\t%d\t%d\n", x, ebp1(x), ebp2(x));
x = 7;
printf("%d\t%d\t%d\n", x, ebp1(x), ebp2(x));
x = 21;
printf("%d\t%d\t%d\n", x, ebp1(x), ebp2(x));
}
int ebp1(int x){
int masker = (0x55 << 8)+0x55;
masker = (masker<<16)+masker;
x = x&masker;
x = x ^ (x >> 1);
x = x ^ (x >> 2);
x = x ^ (x >> 4);
x = x ^ (x >> 8);
x = x ^ (x >> 16);
return x&1;
}
int ebp2(int x){
x = x ^ (x >> 2);
x = x ^ (x >> 4);
x = x ^ (x >> 8);
x = x ^ (x >> 16);
return x&1;
}

The Two Water Jug Puzzle

I am trying to solve the two WATER JUG PUZZLE using euclidean algorithm and Diophantine equation.
let gcd(m,n) = g
using euclidean aldortihm we get X' and Y' such that mX' + nY' = g
for mX + nY = d
if d%g!= 0 no solution exists
else i made X' as X' / g * d and Y' as Y' / g * d
this is one solution for mX + nY = d
now multiple solutions by m ( X' + ( k * n / g ) ) + n ( Y' - ( m * k / g ) ) = d
i just needed to output the SUM OF NO. OPERATIONS
so, i think of the solution as X' + Y' + k * ( n - m ) / g and i want to minimise this
my code below for the same (its giving wrong answers...)
int X, Y;
int gcd(int a, int b)
{
if (b == 0)
{
X = 1;
Y = 0;
return a;
}
int g = gcd(b, a % b);
int X1 = Y;
int Y1 = X - (a / b) * Y;
X = X1;
Y = Y1;
return g;
}
cin >> m >> n >> d;
int g = gcd(n, m);
if (d % g)
cout << -1 << endl;
else
{
X = X / g * d;
Y = Y / g * d;
int ans = X + Y;
int mn = ans;
while (ans > 0)
{
ans += ((m - n) / g);
mn = min(ans, mn);
}
while (ans < 10000)
{
ans += ((n - m) / g);
mn = min(ans, mn);
}
cout << mn << endl;
}

Erasing Polygon Overlay in Spatial Analysis

I am using Sutherland Hodgman's Algorithm inorder to clip the polygon overlay for clipping Spatial Query. And I want to implement erase overlay function as well. So suggest me some algorithm like Sutherland Hodgman Algorithm or Can anyone modify this Sutherland Hodgman Algorithm for me.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct { double x, y; } vec_t, *vec;
inline double dot(vec a, vec b)
{
return a->x * b->x + a->y * b->y;
}
inline double cross(vec a, vec b)
{
return a->x * b->y - a->y * b->x;
}
inline vec vsub(vec a, vec b, vec res)
{
res->x = a->x - b->x;
res->y = a->y - b->y;
return res;
}
/* tells if vec c lies on the left side of directed edge a->b
* 1 if left, -1 if right, 0 if colinear
*/
int left_of(vec a, vec b, vec c)
{
vec_t tmp1, tmp2;
double x;
vsub(b, a, &tmp1);
vsub(c, b, &tmp2);
x = cross(&tmp1, &tmp2);
return x < 0 ? -1 : x > 0;
}
int line_sect(vec x0, vec x1, vec y0, vec y1, vec res)
{
vec_t dx, dy, d;
vsub(x1, x0, &dx);
vsub(y1, y0, &dy);
vsub(x0, y0, &d);
/* x0 + a dx = y0 + b dy ->
x0 X dx = y0 X dx + b dy X dx ->
b = (x0 - y0) X dx / (dy X dx) */
double dyx = cross(&dy, &dx);
if (!dyx) return 0;
dyx = cross(&d, &dx) / dyx;
if (dyx <= 0 || dyx >= 1) return 0;
res->x = y0->x + dyx * dy.x;
res->y = y0->y + dyx * dy.y;
return 1;
}
/* === polygon stuff === */
typedef struct { int len, alloc; vec v; } poly_t, *poly;
poly poly_new()
{
poly p = (poly)malloc(sizeof(poly_t));
p->len = p->alloc = 0;
p->v = 0;
return p;
}
void poly_free(poly p)
{
if (p->alloc) {
free(p->v);
free(p);
}
}
void poly_append(poly p, vec v)
{
if (p->len >= p->alloc) {
p->alloc *= 2;
if (!p->alloc) p->alloc = 4;
p->v = (vec)realloc(p->v, sizeof(vec_t) * p->alloc);
}
p->v[p->len++] = *v;
}
/* this works only if all of the following are true:
* 1. poly has no colinear edges;
* 2. poly has no duplicate vertices;
* 3. poly has at least three vertices;
* 4. poly is convex (implying 3).
*/
int poly_winding(poly p)
{
return left_of(&p->v[0], &p->v[1], &p->v[2]);
}
void poly_edge_clip(poly sub, vec x0, vec x1, int left, poly res)
{
int i, side0, side1;
vec_t tmp;
vec v0 = &sub->v[sub->len - 1], v1;
res->len = 0;
side0 = left_of(x0, x1, v0);
if (side0 != -left) poly_append(res, v0);
for (i = 0; i < sub->len; i++) {
v1 = &sub->v[i];
side1 = left_of(x0, x1, v1);
if (side0 + side1 == 0 && side0)
/* last point and current straddle the edge */
if (line_sect(x0, x1, v0, v1, &tmp))
poly_append(res, &tmp);
if (i == sub->len - 1) break;
if (side1 != -left) poly_append(res, v1);
v0 = v1;
side0 = side1;
}
}
poly poly_clip(poly sub, poly clip)
{
int i;
poly p1 = poly_new(), p2 = poly_new(), tmp;
int dir = poly_winding(clip);
poly_edge_clip(sub, &clip->v[clip->len - 1], &clip->v[0], dir, p2);
for (i = 0; i < clip->len - 1; i++) {
tmp = p2; p2 = p1; p1 = tmp;
poly_edge_clip(p1, &clip->v[i], &clip->v[i + 1], dir, p2);
}
poly_free(p1);
return p2;
}
int main()
{
int i;
vec_t c[] = {{200,200}, {400,200}, {400,400}, {200,400}};
//vec_t c[] = {{100,300}, {300,300}, {300,100}, {100,100}};
vec_t s[] = { {50,150}, {200,50}, {350,150},
{350,300},{250,300},{200,250},
{150,350},{100,250},{100,200}};
#define clen (sizeof(c)/sizeof(vec_t))
#define slen (sizeof(s)/sizeof(vec_t))
poly_t clipper = {clen, 0, c};
poly_t subject = {slen, 0, s};
poly res = poly_clip(&subject, &clipper);
for (i = 0; i < res->len; i++)
printf("%g %g\n", res->v[i].x, res->v[i].y);
/* long and arduous EPS printout */
FILE * eps = fopen("test.eps", "w");
fprintf(eps, "%%!PS-Adobe-3.0\n%%%%BoundingBox: 40 40 360 360\n"
"/l {lineto} def /m{moveto} def /s{setrgbcolor} def"
"/c {closepath} def /gs {fill grestore stroke} def\n");
fprintf(eps, "0 setlinewidth %g %g m ", c[0].x, c[0].y);
for (i = 1; i < clen; i++)
fprintf(eps, "%g %g l ", c[i].x, c[i].y);
fprintf(eps, "c .5 0 0 s gsave 1 .7 .7 s gs\n");
fprintf(eps, "%g %g m ", s[0].x, s[0].y);
for (i = 1; i < slen; i++)
fprintf(eps, "%g %g l ", s[i].x, s[i].y);
fprintf(eps, "c 0 .2 .5 s gsave .4 .7 1 s gs\n");
fprintf(eps, "2 setlinewidth [10 8] 0 setdash %g %g m ",
res->v[0].x, res->v[0].y);
for (i = 1; i < res->len; i++)
fprintf(eps, "%g %g l ", res->v[i].x, res->v[i].y);
fprintf(eps, "c .5 0 .5 s gsave .7 .3 .8 s gs\n");
fprintf(eps, "%%%%EOF");
fclose(eps);
printf("test.eps written\n");
return 0;
}

Bitwise integer cube root algorithm

Here is a simple way to calculate an integer square root:
int isqrt(int num)
{
int root=0;
int b = 0x8000;
int a=0, c=0;
while (b) {
c = a|b;
if (c*c <= num)
a |= b;
b >>= 1;
}
}
Ingeniously (thanks Wikipedia), this can be optimised like this:
int sqrt(short num)
{
int op = num;
int res = 0;
int one = 1 << 30;
while (one > op)
one >>= 2;
while (one != 0) {
if (op >= res + one) {
op -= res + one;
res = (res >> 1) + one;
}
else
res >>= 1;
one >>= 2;
}
return res;
}
My question: Can a similarly optimised algorithm be written for an integer cube root? (This is to be run on a small microcontroller which prefers not to do multiplications)
According to this SO question and to the answer marked, from the Hacker's Delight book you can find this implementation:
int icbrt2(unsigned x) {
int s;
unsigned y, b, y2;
y2 = 0;
y = 0;
for (s = 30; s >= 0; s = s - 3) {
y2 = 4*y2;
y = 2*y;
b = (3*(y2 + y) + 1) << s;
if (x >= b) {
x = x - b;
y2 = y2 + 2*y + 1;
y = y + 1;
}
}
return y;
}
This is an (extreme) C# optimized version of the Hacker's Delight code, as mentioned by others.
For reference (on my pc): Math.Sqrt takes about 35 ns, cbrt < 15 ns.
Multiplications by small numbers are used, but it's easy to replace them with shifts and
adds. For example the largest multipication (last line):
"12 * z" ==> "(z << 3) + (z << 2)"
It's difficult to judge whether the size of the code is acceptable for a small microcontroller.
First step: A binary search, the "if" statements, large values ( >= 1u << 24 ) are found relatively faster, small values ( < 64 ) are handled during the search.
Second step: A jump into the unrolled loop, the "labels".
private static uint cbrt(uint x)
{
uint y = 2, z = 4, b = 0;
if (x < 1u << 24)
if (x < 1u << 12)
if (x < 1u << 06)
if (x < 1u << 03)
return x == 0u ? 0u : 1u;
else
return x < 27u ? 2u : 3u;
else
if (x < 1u << 09) goto L8; else goto L7;
else
if (x < 1u << 18)
if (x < 1u << 15) goto L6; else goto L5;
else
if (x < 1u << 21) goto L4; else goto L3;
else
if (x >= 1u << 30) goto L0;
else
if (x < 1u << 27) goto L2; else goto L1;
L0: x -= 1u << 30; if (x >= 19u << 27)
{ x -= 19u << 27; z = 9; y = 3; } goto M0;
L1: x -= 1u << 27; if (x >= 19u << 24)
{ x -= 19u << 24; z = 9; y = 3; } goto M1;
L2: x -= 1u << 24; if (x >= 19u << 21)
{ x -= 19u << 21; z = 9; y = 3; } goto M2;
L3: x -= 1u << 21; if (x >= 19u << 18)
{ x -= 19u << 18; z = 9; y = 3; } goto M3;
L4: x -= 1u << 18; if (x >= 19u << 15)
{ x -= 19u << 15; z = 9; y = 3; } goto M4;
L5: x -= 1u << 15; if (x >= 19u << 12)
{ x -= 19u << 12; z = 9; y = 3; } goto M5;
L6: x -= 1u << 12; if (x >= 19u << 09)
{ x -= 19u << 09; z = 9; y = 3; } goto M6;
L7: x -= 1u << 09; if (x >= 19u << 06)
{ x -= 19u << 06; z = 9; y = 3; } goto M7;
L8: x -= 1u << 06; if (x >= 19u << 03)
{ x -= 19u << 03; z = 9; y = 3; } goto M8;
M0: y *= 2; z *= 4; b = 3 * y + 3 * z + 1 << 24;
if (x >= b) { x -= b; z += 2 * y + 1; y += 1; }
M1: y *= 2; z *= 4; b = 3 * y + 3 * z + 1 << 21;
if (x >= b) { x -= b; z += 2 * y + 1; y += 1; }
M2: y *= 2; z *= 4; b = 3 * y + 3 * z + 1 << 18;
if (x >= b) { x -= b; z += 2 * y + 1; y += 1; }
M3: y *= 2; z *= 4; b = 3 * y + 3 * z + 1 << 15;
if (x >= b) { x -= b; z += 2 * y + 1; y += 1; }
M4: y *= 2; z *= 4; b = 3 * y + 3 * z + 1 << 12;
if (x >= b) { x -= b; z += 2 * y + 1; y += 1; }
M5: y *= 2; z *= 4; b = 3 * y + 3 * z + 1 << 09;
if (x >= b) { x -= b; z += 2 * y + 1; y += 1; }
M6: y *= 2; z *= 4; b = 3 * y + 3 * z + 1 << 06;
if (x >= b) { x -= b; z += 2 * y + 1; y += 1; }
M7: y *= 2; z *= 4; b = 3 * y + 3 * z + 1 << 03;
if (x >= b) { x -= b; z += 2 * y + 1; y += 1; }
M8: y *= 2; return x <= 3 * y + 12 * z ? y : y + 1;
}

Resources