#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
typedef uint32_t I_TYPE;
int FIG = 5;
I_TYPE RADIX = 100000;
const double pi = 3.1415926535897932385;
double cos1;
double sin1;
double err_max;
#define max(a,b) ((a)<(b)?(b):(a))
void fr(double* s1, double* s2, double* end, size_t add, size_t t90) {
for (; s1 < end; s1 += add, s2 += add) {
double r0, r1, r2, r3, m0, m1;
r0 = s1[0];
r1 = s2[0];
r2 = s1[t90];
r3 = s2[t90];
m0 = r2 * cos1 - r3 * sin1;
m1 = r2 * sin1 + r3 * cos1;
s1[0] = r0 + m0;
s2[0] = r0 - m0;
s1[t90] = -r1 + m1;
s2[t90] = r1 + m1;
}
}
void fri(double* s1, double* s2, double* end, size_t add, size_t t90) {
for (; s1 < end; s1 += add, s2 += add) {
double r0, r1, r2, r3, m0, m1, m2, m3;
r0 = s1[0];
r1 = s2[0];
r2 = s1[t90];
r3 = s2[t90];
m0 = r0 + r1;
m1 = -r2 + r3;
m2 = r0 - r1;
m3 = r2 + r3;
s1[0] = m0;
s2[0] = m1;
s1[t90] = m2 * cos1 + m3 * sin1;
s2[t90] = -m2 * sin1 + m3 * cos1;
}
}
void fr0(double* s1, double* end, size_t add, size_t t90) {
for (; s1 < end; s1 += add) {
double r0, r1;
r0 = s1[0];
r1 = s1[t90];
s1[0] = r0 + r1;
s1[t90] = r0 - r1;
}
}
void swap_d(double* a, double* b) {
double t = *a;
*a = *b;
*b = t;
}
void bxchg(double* s, int p) {
size_t t4, t5, t6, t045, t090, t180, t270;
t045 = (size_t)1 << p - 3;
t090 = t045 + t045;
t180 = t090 + t090;
t270 = t180 + t090;
t4 = t090 - 4;
t5 = t4;
do {
swap_d(&s[t4 + 1], &s[t180 + t5]);
swap_d(&s[t4 + 2], &s[t090 + t5]);
swap_d(&s[t4 + 3], &s[t270 + t5]);
swap_d(&s[t090 + t4 + 1], &s[t180 + t5 + 2]);
swap_d(&s[t090 + t4 + 3], &s[t270 + t5 + 2]);
swap_d(&s[t180 + t4 + 3], &s[t270 + t5 + 1]);
if (t4 < t5) {
swap_d(&s[t4], &s[t5]);
swap_d(&s[t090 + t4 + 2], &s[t090 + t5 + 2]);
swap_d(&s[t180 + t4 + 1], &s[t180 + t5 + 1]);
swap_d(&s[t270 + t4 + 3], &s[t270 + t5 + 3]);
}
if (t4 == 0) {
break;
}
t4 -= 4;
t6 = t045;
for (;;) {
t5 ^= t6;
if ((t5 & t6) == 0) {
break;
}
t6 >>= 1;
}
} while (1);
}
void bitexchg(double* s, int p) {
if (p <= 1) {
}
else if (p == 2) {
swap_d(&s[1], &s[2]);
}
else if (p == 3) {
swap_d(&s[1], &s[4]);
swap_d(&s[3], &s[6]);
}
else {
bxchg(s, p);
}
}
double* SIN_TABLE[64] = { 0 };
const double* sin_table(int p) {
if (p >= 2 && SIN_TABLE[p] == 0) {
size_t t090, i;
double k;
t090 = (size_t)1 << p - 2;
SIN_TABLE
[p
] = (double*)malloc(t090
* sizeof(double)); if (SIN_TABLE[p] == NULL) {
printf("malloc failed. sin_table %d\r\n", p
); }
k = 0.5 * pi / t090;
for (i = 0; i < t090; i++) {
SIN_TABLE
[p
][i
] = sin(k
* i
); }
}
return SIN_TABLE[p];
}
void fouri(double* s, int p) {
const double* table;
size_t t090, t360;
int i;
table = sin_table(p);
t360 = (size_t)1 << p;
t090 = t360 >> 2;
bitexchg(s, p);
for (i = 1; i <= p; i++) {
size_t r090, r180, r360, k1, k2, t0, t1, t2;
r360 = (size_t)1 << i;
r180 = r360 >> 1;
r090 = r180 >> 1;
fr0(&s[0], &s[t360], r360, r180);
k1 = 1;
k2 = r180 - 1;
t2 = (size_t)1 << p - i;
t0 = t2;
t1 = t090 - t2;
for (; k1 < r090; k1++, k2--) {
sin1 = table[t0];
cos1 = table[t1];
fr(&s[k1], &s[k2], &s[t360], r360, r180);
t0 += t2;
t1 -= t2;
}
}
}
void fouriinv(double* s, int p) {
const double* table;
size_t t090, t360;
int i;
table = sin_table(p);
t360 = (size_t)1 << p;
t090 = t360 >> 2;
for (i = p; i >= 1; i--) {
size_t r090, r180, r360, k1, k2, t0, t1, t2;
r360 = (size_t)1 << i;
r180 = r360 >> 1;
r090 = r180 >> 1;
fr0(&s[0], &s[t360], r360, r180);
k1 = 1;
k2 = r180 - 1;
t2 = (size_t)1 << p - i;
t0 = t2;
t1 = t090 - t2;
for (; k1 < r090; k1++, k2--) {
sin1 = table[t0];
cos1 = table[t1];
fri(&s[k1], &s[k2], &s[t360], r360, r180);
t0 += t2;
t1 -= t2;
}
}
bitexchg(s, p);
}
typedef struct I_ {
I_TYPE* data;
size_t capacity;
size_t size;
} I;
typedef struct F_ {
double* data;
size_t capacity;
int p;
} F;
void alloc_i(I* a, size_t cap) {
a
->data
= (I_TYPE
*)malloc(cap
* sizeof(I_TYPE
)); if (a->data == NULL) {
printf("malloc failed. alloc_i %zu\r\n", cap
); }
a->capacity = cap;
}
void free_i(I* a) {
}
void alloc_f(F* a, int p) {
size_t cap = (size_t)1 << p;
a
->data
= (double*)malloc(cap
* sizeof(double)); if (a->data == NULL) {
printf("malloc failed. alloc_f %d\r\n", p
); }
a->capacity = cap;
}
void free_f(F* a) {
}
void swap_i(I* a, I* b) {
I t = *a;
*a = *b;
*b = t;
}
void i2f(F* a, const I* b, int p) {
size_t i;
size_t t360;
int carry;
t360 = (size_t)1 << p;
a->p = p;
carry = 0;
for (i = 0; i < b->size - 1; i++) {
int t = b->data[i] + carry;
if (t < (int)RADIX / 2) {
a->data[i] = t;
carry = 0;
}
else {
a->data[i] = (int)t - (int)RADIX;
carry = 1;
}
}
a->data[i] = b->data[i] + carry;
i++;
for (; i < t360; i++) {
a->data[i] = 0.;
}
fouri(a->data, p);
}
void mul_f2i(I* a, const F* b, const F* c, F* d) {
int p;
size_t i, s, t, t180, t360, k1, k2;
int64_t carry;
double k;
p = b->p;
t180 = (size_t)1 << p - 1;
t360 = t180 + t180;
d->data[0] = b->data[0] * c->data[0] * .5;
d->data[t180] = b->data[t180] * c->data[t180] * .5;
k1 = 1;
k2 = t360 - 1;
for (; k1 < t180; k1++, k2--) {
double re, im;
re = b->data[k1] * c->data[k1] - b->data[k2] * c->data[k2];
im = b->data[k1] * c->data[k2] + b->data[k2] * c->data[k1];
d->data[k1] = re;
d->data[k2] = im;
}
fouriinv(d->data, p);
s = a->capacity < t360 ? a->capacity : t360;
carry = 0;
t = 1;
for (i = 0; i < s; i++) {
double x;
int64_t e, f;
x = d->data[i] * k;
e
= (int64_t)floor(x
+ .5); err_max
= max
(err_max
, fabs(x
- e
)); e += carry;
carry = e / RADIX;
f = e - carry * RADIX;
if (f < 0) {
f += RADIX;
carry--;
}
a->data[i] = (I_TYPE)f;
if (f != 0) {
t = i + 1;
}
}
a->size = t;
if (carry != 0) {
if (a->size < a->capacity) {
assert(0 <= carry
&& carry
< RADIX
); a->data[a->size++] = (I_TYPE)carry;
}
else {
}
}
for (; i < t360; i++) {
double x;
int64_t e;
x = d->data[i] * k;
e
= (int64_t)floor(x
+ .5); err_max
= max
(err_max
, fabs(x
- e
)); }
}
void add_i(I* a, const I* b, const I* c) {
I_TYPE carry, d;
size_t i;
if (b->size > c->size) {
const I* t = b;
b = c;
c = t;
}
assert(c
->size
<= a
->capacity
);
carry = 0;
for (i = 0; i < b->size; i++) {
d = b->data[i] + c->data[i] + carry;
carry = 0;
if (d >= RADIX) {
d -= RADIX;
carry++;
}
a->data[i] = d;
}
for (; i < c->size; i++) {
d = c->data[i] + carry;
carry = 0;
if (d >= RADIX) {
d -= RADIX;
carry++;
}
a->data[i] = d;
}
a->size = c->size;
if (carry != 0) {
a->data[a->size++] = carry;
assert(a
->size
<= a
->capacity
); }
}
void print(const char* filename, const I* a) {
char format[10];
size_t s;
FILE* fp;
assert(a
->size
<= a
->capacity
);
fp
= fopen(filename
, "w");
s = a->size;
while (s != 0) {
}
}
int s2p(size_t s1, size_t s2) {
int i;
for (i = 1; i < 64; i++) {
if (((size_t)1 << i) + 1 >= s1 + s2) {
break;
}
}
return i;
}
int main(int argc, char** argv) {
int n = 34;
I a;
F x;
int p
= s2p
((1llu
<< n
) * log(2) / log(10) / FIG
+ 1, 1); size_t cap = (size_t)1 << p;
alloc_i(&a, cap);
alloc_f(&x, p);
a.data[0] = 1;
a.size = 1;
for (int i = 0; i < n; i++) {
int p = s2p(a.size, a.size);
i2f(&x, &a, p);
mul_f2i(&a, &x, &x, &x);
add_i(&a, &a, &a);
{
char filename[200];
print(filename, &a);
}
printf("%d %f\n", i
+ 1, err_max
); }
free_i(&a);
free_f(&x);
return 0;
}
I2luY2x1ZGUgPHN0ZGludC5oPgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8bWF0aC5oPgojaW5jbHVkZSA8YXNzZXJ0Lmg+Cgp0eXBlZGVmIHVpbnQzMl90IElfVFlQRTsKCmludCBGSUcgPSA1OwpJX1RZUEUgUkFESVggPSAxMDAwMDA7Cgpjb25zdCBkb3VibGUgcGkgPSAzLjE0MTU5MjY1MzU4OTc5MzIzODU7Cgpkb3VibGUgY29zMTsKZG91YmxlIHNpbjE7CmRvdWJsZSBlcnJfbWF4OwoKI2RlZmluZSBtYXgoYSxiKQkJKChhKTwoYik/KGIpOihhKSkKCnZvaWQgZnIoZG91YmxlKiBzMSwgZG91YmxlKiBzMiwgZG91YmxlKiBlbmQsIHNpemVfdCBhZGQsIHNpemVfdCB0OTApIHsKCWZvciAoOyBzMSA8IGVuZDsgczEgKz0gYWRkLCBzMiArPSBhZGQpIHsKCQlkb3VibGUgcjAsIHIxLCByMiwgcjMsIG0wLCBtMTsKCgkJcjAgPSBzMVswXTsKCQlyMSA9IHMyWzBdOwoJCXIyID0gczFbdDkwXTsKCQlyMyA9IHMyW3Q5MF07CgoJCW0wID0gcjIgKiBjb3MxIC0gcjMgKiBzaW4xOwoJCW0xID0gcjIgKiBzaW4xICsgcjMgKiBjb3MxOwoKCQlzMVswXSA9IHIwICsgbTA7CgkJczJbMF0gPSByMCAtIG0wOwoJCXMxW3Q5MF0gPSAtcjEgKyBtMTsKCQlzMlt0OTBdID0gcjEgKyBtMTsKCX0KfQoKdm9pZCBmcmkoZG91YmxlKiBzMSwgZG91YmxlKiBzMiwgZG91YmxlKiBlbmQsIHNpemVfdCBhZGQsIHNpemVfdCB0OTApIHsKCWZvciAoOyBzMSA8IGVuZDsgczEgKz0gYWRkLCBzMiArPSBhZGQpIHsKCQlkb3VibGUgcjAsIHIxLCByMiwgcjMsIG0wLCBtMSwgbTIsIG0zOwoKCQlyMCA9IHMxWzBdOwoJCXIxID0gczJbMF07CgkJcjIgPSBzMVt0OTBdOwoJCXIzID0gczJbdDkwXTsKCgkJbTAgPSByMCArIHIxOwoJCW0xID0gLXIyICsgcjM7CgkJbTIgPSByMCAtIHIxOwoJCW0zID0gcjIgKyByMzsKCgkJczFbMF0gPSBtMDsKCQlzMlswXSA9IG0xOwoJCXMxW3Q5MF0gPSBtMiAqIGNvczEgKyBtMyAqIHNpbjE7CgkJczJbdDkwXSA9IC1tMiAqIHNpbjEgKyBtMyAqIGNvczE7Cgl9Cn0KCnZvaWQgZnIwKGRvdWJsZSogczEsIGRvdWJsZSogZW5kLCBzaXplX3QgYWRkLCBzaXplX3QgdDkwKSB7Cglmb3IgKDsgczEgPCBlbmQ7IHMxICs9IGFkZCkgewoJCWRvdWJsZSByMCwgcjE7CgoJCXIwID0gczFbMF07CgkJcjEgPSBzMVt0OTBdOwoKCQlzMVswXSA9IHIwICsgcjE7CgkJczFbdDkwXSA9IHIwIC0gcjE7Cgl9Cn0KCnZvaWQgc3dhcF9kKGRvdWJsZSogYSwgZG91YmxlKiBiKSB7Cglkb3VibGUgdCA9ICphOwoJKmEgPSAqYjsKCSpiID0gdDsKfQoKdm9pZCBieGNoZyhkb3VibGUqIHMsIGludCBwKSB7CglzaXplX3QgdDQsIHQ1LCB0NiwgdDA0NSwgdDA5MCwgdDE4MCwgdDI3MDsKCgl0MDQ1ID0gKHNpemVfdCkxIDw8IHAgLSAzOwoJdDA5MCA9IHQwNDUgKyB0MDQ1OwoJdDE4MCA9IHQwOTAgKyB0MDkwOwoJdDI3MCA9IHQxODAgKyB0MDkwOwoKCXQ0ID0gdDA5MCAtIDQ7Cgl0NSA9IHQ0OwoJZG8gewoJCXN3YXBfZCgmc1t0NCArIDFdLCAmc1t0MTgwICsgdDVdKTsKCQlzd2FwX2QoJnNbdDQgKyAyXSwgJnNbdDA5MCArIHQ1XSk7CgkJc3dhcF9kKCZzW3Q0ICsgM10sICZzW3QyNzAgKyB0NV0pOwoJCXN3YXBfZCgmc1t0MDkwICsgdDQgKyAxXSwgJnNbdDE4MCArIHQ1ICsgMl0pOwoJCXN3YXBfZCgmc1t0MDkwICsgdDQgKyAzXSwgJnNbdDI3MCArIHQ1ICsgMl0pOwoJCXN3YXBfZCgmc1t0MTgwICsgdDQgKyAzXSwgJnNbdDI3MCArIHQ1ICsgMV0pOwoKCQlpZiAodDQgPCB0NSkgewoJCQlzd2FwX2QoJnNbdDRdLCAmc1t0NV0pOwoJCQlzd2FwX2QoJnNbdDA5MCArIHQ0ICsgMl0sICZzW3QwOTAgKyB0NSArIDJdKTsKCQkJc3dhcF9kKCZzW3QxODAgKyB0NCArIDFdLCAmc1t0MTgwICsgdDUgKyAxXSk7CgkJCXN3YXBfZCgmc1t0MjcwICsgdDQgKyAzXSwgJnNbdDI3MCArIHQ1ICsgM10pOwoJCX0KCQlpZiAodDQgPT0gMCkgewoJCQlicmVhazsKCQl9CgoJCXQ0IC09IDQ7CgkJdDYgPSB0MDQ1OwoJCWZvciAoOzspIHsKCQkJdDUgXj0gdDY7CgkJCWlmICgodDUgJiB0NikgPT0gMCkgewoJCQkJYnJlYWs7CgkJCX0KCQkJdDYgPj49IDE7CgkJfQoJfSB3aGlsZSAoMSk7Cn0KCnZvaWQgYml0ZXhjaGcoZG91YmxlKiBzLCBpbnQgcCkgewoJaWYgKHAgPD0gMSkgewoJfQoJZWxzZSBpZiAocCA9PSAyKSB7CgkJc3dhcF9kKCZzWzFdLCAmc1syXSk7Cgl9CgllbHNlIGlmIChwID09IDMpIHsKCQlzd2FwX2QoJnNbMV0sICZzWzRdKTsKCQlzd2FwX2QoJnNbM10sICZzWzZdKTsKCX0KCWVsc2UgewoJCWJ4Y2hnKHMsIHApOwoJfQp9Cgpkb3VibGUqIFNJTl9UQUJMRVs2NF0gPSB7IDAgfTsKCmNvbnN0IGRvdWJsZSogc2luX3RhYmxlKGludCBwKSB7CglpZiAocCA+PSAyICYmIFNJTl9UQUJMRVtwXSA9PSAwKSB7CgkJc2l6ZV90IHQwOTAsIGk7CgkJZG91YmxlIGs7CgoJCXQwOTAgPSAoc2l6ZV90KTEgPDwgcCAtIDI7CgkJU0lOX1RBQkxFW3BdID0gKGRvdWJsZSopbWFsbG9jKHQwOTAgKiBzaXplb2YoZG91YmxlKSk7CgkJaWYgKFNJTl9UQUJMRVtwXSA9PSBOVUxMKSB7CgkJCXByaW50ZigibWFsbG9jIGZhaWxlZC4gc2luX3RhYmxlICVkXHJcbiIsIHApOwoJCQlleGl0KDApOwoJCX0KCQlrID0gMC41ICogcGkgLyB0MDkwOwoJCWZvciAoaSA9IDA7IGkgPCB0MDkwOyBpKyspIHsKCQkJU0lOX1RBQkxFW3BdW2ldID0gc2luKGsgKiBpKTsKCQl9Cgl9CglyZXR1cm4gU0lOX1RBQkxFW3BdOwp9Cgp2b2lkIGZvdXJpKGRvdWJsZSogcywgaW50IHApIHsKCWNvbnN0IGRvdWJsZSogdGFibGU7CglzaXplX3QgdDA5MCwgdDM2MDsKCWludCBpOwoKCXRhYmxlID0gc2luX3RhYmxlKHApOwoJdDM2MCA9IChzaXplX3QpMSA8PCBwOwoJdDA5MCA9IHQzNjAgPj4gMjsKCgliaXRleGNoZyhzLCBwKTsKCglmb3IgKGkgPSAxOyBpIDw9IHA7IGkrKykgewoJCXNpemVfdCByMDkwLCByMTgwLCByMzYwLCBrMSwgazIsIHQwLCB0MSwgdDI7CgoJCXIzNjAgPSAoc2l6ZV90KTEgPDwgaTsKCQlyMTgwID0gcjM2MCA+PiAxOwoJCXIwOTAgPSByMTgwID4+IDE7CgoJCWZyMCgmc1swXSwgJnNbdDM2MF0sIHIzNjAsIHIxODApOwoKCQlrMSA9IDE7CgkJazIgPSByMTgwIC0gMTsKCQl0MiA9IChzaXplX3QpMSA8PCBwIC0gaTsKCQl0MCA9IHQyOwoJCXQxID0gdDA5MCAtIHQyOwoJCWZvciAoOyBrMSA8IHIwOTA7IGsxKyssIGsyLS0pIHsKCQkJc2luMSA9IHRhYmxlW3QwXTsKCQkJY29zMSA9IHRhYmxlW3QxXTsKCQkJZnIoJnNbazFdLCAmc1trMl0sICZzW3QzNjBdLCByMzYwLCByMTgwKTsKCQkJdDAgKz0gdDI7CgkJCXQxIC09IHQyOwoJCX0KCX0KfQoKdm9pZCBmb3VyaWludihkb3VibGUqIHMsIGludCBwKSB7Cgljb25zdCBkb3VibGUqIHRhYmxlOwoJc2l6ZV90IHQwOTAsIHQzNjA7CglpbnQgaTsKCgl0YWJsZSA9IHNpbl90YWJsZShwKTsKCXQzNjAgPSAoc2l6ZV90KTEgPDwgcDsKCXQwOTAgPSB0MzYwID4+IDI7CgoJZm9yIChpID0gcDsgaSA+PSAxOyBpLS0pIHsKCQlzaXplX3QgcjA5MCwgcjE4MCwgcjM2MCwgazEsIGsyLCB0MCwgdDEsIHQyOwoKCQlyMzYwID0gKHNpemVfdCkxIDw8IGk7CgkJcjE4MCA9IHIzNjAgPj4gMTsKCQlyMDkwID0gcjE4MCA+PiAxOwoKCQlmcjAoJnNbMF0sICZzW3QzNjBdLCByMzYwLCByMTgwKTsKCgkJazEgPSAxOwoJCWsyID0gcjE4MCAtIDE7CgkJdDIgPSAoc2l6ZV90KTEgPDwgcCAtIGk7CgkJdDAgPSB0MjsKCQl0MSA9IHQwOTAgLSB0MjsKCQlmb3IgKDsgazEgPCByMDkwOyBrMSsrLCBrMi0tKSB7CgkJCXNpbjEgPSB0YWJsZVt0MF07CgkJCWNvczEgPSB0YWJsZVt0MV07CgkJCWZyaSgmc1trMV0sICZzW2syXSwgJnNbdDM2MF0sIHIzNjAsIHIxODApOwoJCQl0MCArPSB0MjsKCQkJdDEgLT0gdDI7CgkJfQoJfQoJYml0ZXhjaGcocywgcCk7Cn0KCnR5cGVkZWYgc3RydWN0IElfIHsKCUlfVFlQRSogZGF0YTsKCXNpemVfdCBjYXBhY2l0eTsKCXNpemVfdCBzaXplOwp9IEk7Cgp0eXBlZGVmIHN0cnVjdCBGXyB7Cglkb3VibGUqIGRhdGE7CglzaXplX3QgY2FwYWNpdHk7CglpbnQgcDsKfSBGOwoKdm9pZCBhbGxvY19pKEkqIGEsIHNpemVfdCBjYXApIHsKCWEtPmRhdGEgPSAoSV9UWVBFKiltYWxsb2MoY2FwICogc2l6ZW9mKElfVFlQRSkpOwoJaWYgKGEtPmRhdGEgPT0gTlVMTCkgewoJCXByaW50ZigibWFsbG9jIGZhaWxlZC4gYWxsb2NfaSAlenVcclxuIiwgY2FwKTsKCQlleGl0KDApOwoJfQoJYS0+Y2FwYWNpdHkgPSBjYXA7Cn0KCnZvaWQgZnJlZV9pKEkqIGEpIHsKCWZyZWUoYS0+ZGF0YSk7Cn0KCnZvaWQgYWxsb2NfZihGKiBhLCBpbnQgcCkgewoJc2l6ZV90IGNhcCA9IChzaXplX3QpMSA8PCBwOwoJYS0+ZGF0YSA9IChkb3VibGUqKW1hbGxvYyhjYXAgKiBzaXplb2YoZG91YmxlKSk7CglpZiAoYS0+ZGF0YSA9PSBOVUxMKSB7CgkJcHJpbnRmKCJtYWxsb2MgZmFpbGVkLiBhbGxvY19mICVkXHJcbiIsIHApOwoJCWV4aXQoMCk7Cgl9CglhLT5jYXBhY2l0eSA9IGNhcDsKfQoKdm9pZCBmcmVlX2YoRiogYSkgewoJZnJlZShhLT5kYXRhKTsKfQoKdm9pZCBzd2FwX2koSSogYSwgSSogYikgewoJSSB0ID0gKmE7CgkqYSA9ICpiOwoJKmIgPSB0Owp9Cgp2b2lkIGkyZihGKiBhLCBjb25zdCBJKiBiLCBpbnQgcCkgewoJc2l6ZV90IGk7CglzaXplX3QgdDM2MDsKCWludCBjYXJyeTsKCgl0MzYwID0gKHNpemVfdCkxIDw8IHA7CgoJYXNzZXJ0KGItPnNpemUgPD0gdDM2MCk7Cglhc3NlcnQodDM2MCA8PSBhLT5jYXBhY2l0eSk7CgoJYS0+cCA9IHA7CgljYXJyeSA9IDA7Cglmb3IgKGkgPSAwOyBpIDwgYi0+c2l6ZSAtIDE7IGkrKykgewoJCWludCB0ID0gYi0+ZGF0YVtpXSArIGNhcnJ5OwoJCWlmICh0IDwgKGludClSQURJWCAvIDIpIHsKCQkJYS0+ZGF0YVtpXSA9IHQ7CgkJCWNhcnJ5ID0gMDsKCQl9CgkJZWxzZSB7CgkJCWEtPmRhdGFbaV0gPSAoaW50KXQgLSAoaW50KVJBRElYOwoJCQljYXJyeSA9IDE7CgkJfQoJfQoJYS0+ZGF0YVtpXSA9IGItPmRhdGFbaV0gKyBjYXJyeTsKCWkrKzsKCWZvciAoOyBpIDwgdDM2MDsgaSsrKSB7CgkJYS0+ZGF0YVtpXSA9IDAuOwoJfQoJZm91cmkoYS0+ZGF0YSwgcCk7Cn0KCnZvaWQgbXVsX2YyaShJKiBhLCBjb25zdCBGKiBiLCBjb25zdCBGKiBjLCBGKiBkKSB7CglpbnQgcDsKCXNpemVfdCBpLCBzLCB0LCB0MTgwLCB0MzYwLCBrMSwgazI7CglpbnQ2NF90IGNhcnJ5OwoJZG91YmxlIGs7CgoJcCA9IGItPnA7Cgl0MTgwID0gKHNpemVfdCkxIDw8IHAgLSAxOwoJdDM2MCA9IHQxODAgKyB0MTgwOwoKCWFzc2VydChwID09IGMtPnApOwoJYXNzZXJ0KHQzNjAgPD0gYi0+Y2FwYWNpdHkpOwoJYXNzZXJ0KHQzNjAgPD0gYy0+Y2FwYWNpdHkpOwoJYXNzZXJ0KHQzNjAgPD0gZC0+Y2FwYWNpdHkpOwoKCWQtPmRhdGFbMF0gPSBiLT5kYXRhWzBdICogYy0+ZGF0YVswXSAqIC41OwoJZC0+ZGF0YVt0MTgwXSA9IGItPmRhdGFbdDE4MF0gKiBjLT5kYXRhW3QxODBdICogLjU7CgoJazEgPSAxOwoJazIgPSB0MzYwIC0gMTsKCWZvciAoOyBrMSA8IHQxODA7IGsxKyssIGsyLS0pIHsKCQlkb3VibGUgcmUsIGltOwoKCQlyZSA9IGItPmRhdGFbazFdICogYy0+ZGF0YVtrMV0gLSBiLT5kYXRhW2syXSAqIGMtPmRhdGFbazJdOwoJCWltID0gYi0+ZGF0YVtrMV0gKiBjLT5kYXRhW2syXSArIGItPmRhdGFbazJdICogYy0+ZGF0YVtrMV07CgkJZC0+ZGF0YVtrMV0gPSByZTsKCQlkLT5kYXRhW2syXSA9IGltOwoJfQoKCWZvdXJpaW52KGQtPmRhdGEsIHApOwoKCXMgPSBhLT5jYXBhY2l0eSA8IHQzNjAgPyBhLT5jYXBhY2l0eSA6IHQzNjA7CgoJY2FycnkgPSAwOwoJdCA9IDE7CglrID0gbGRleHAoMS4sIC1wICsgMSk7Cglmb3IgKGkgPSAwOyBpIDwgczsgaSsrKSB7CgkJZG91YmxlIHg7CgkJaW50NjRfdCBlLCBmOwoKCQl4ID0gZC0+ZGF0YVtpXSAqIGs7CgkJZSA9IChpbnQ2NF90KWZsb29yKHggKyAuNSk7CgkJZXJyX21heCA9IG1heChlcnJfbWF4LCBmYWJzKHggLSBlKSk7CgkJZSArPSBjYXJyeTsKCQljYXJyeSA9IGUgLyBSQURJWDsKCQlmID0gZSAtIGNhcnJ5ICogUkFESVg7CgkJaWYgKGYgPCAwKSB7CgkJCWYgKz0gUkFESVg7CgkJCWNhcnJ5LS07CgkJfQoJCWEtPmRhdGFbaV0gPSAoSV9UWVBFKWY7CgkJaWYgKGYgIT0gMCkgewoJCQl0ID0gaSArIDE7CgkJfQoJfQoJYS0+c2l6ZSA9IHQ7CglpZiAoY2FycnkgIT0gMCkgewoJCWlmIChhLT5zaXplIDwgYS0+Y2FwYWNpdHkpIHsKCQkJYXNzZXJ0KDAgPD0gY2FycnkgJiYgY2FycnkgPCBSQURJWCk7CgkJCWEtPmRhdGFbYS0+c2l6ZSsrXSA9IChJX1RZUEUpY2Fycnk7CgkJfQoJCWVsc2UgewoJCQlhc3NlcnQoMCk7CgkJfQoJfQoJZm9yICg7IGkgPCB0MzYwOyBpKyspIHsKCQlkb3VibGUgeDsKCQlpbnQ2NF90IGU7CgoJCXggPSBkLT5kYXRhW2ldICogazsKCQllID0gKGludDY0X3QpZmxvb3IoeCArIC41KTsKCQllcnJfbWF4ID0gbWF4KGVycl9tYXgsIGZhYnMoeCAtIGUpKTsKCQlhc3NlcnQoZSA9PSAwKTsKCX0KfQoKdm9pZCBhZGRfaShJKiBhLCBjb25zdCBJKiBiLCBjb25zdCBJKiBjKSB7CglJX1RZUEUgY2FycnksIGQ7CglzaXplX3QgaTsKCglpZiAoYi0+c2l6ZSA+IGMtPnNpemUpIHsKCQljb25zdCBJKiB0ID0gYjsKCQliID0gYzsKCQljID0gdDsKCX0KCWFzc2VydChjLT5zaXplIDw9IGEtPmNhcGFjaXR5KTsKCgljYXJyeSA9IDA7Cglmb3IgKGkgPSAwOyBpIDwgYi0+c2l6ZTsgaSsrKSB7CgkJZCA9IGItPmRhdGFbaV0gKyBjLT5kYXRhW2ldICsgY2Fycnk7CgkJY2FycnkgPSAwOwoJCWlmIChkID49IFJBRElYKSB7CgkJCWQgLT0gUkFESVg7CgkJCWNhcnJ5Kys7CgkJfQoJCWEtPmRhdGFbaV0gPSBkOwoJfQoJZm9yICg7IGkgPCBjLT5zaXplOyBpKyspIHsKCQlkID0gYy0+ZGF0YVtpXSArIGNhcnJ5OwoJCWNhcnJ5ID0gMDsKCQlpZiAoZCA+PSBSQURJWCkgewoJCQlkIC09IFJBRElYOwoJCQljYXJyeSsrOwoJCX0KCQlhLT5kYXRhW2ldID0gZDsKCX0KCWEtPnNpemUgPSBjLT5zaXplOwoJaWYgKGNhcnJ5ICE9IDApIHsKCQlhLT5kYXRhW2EtPnNpemUrK10gPSBjYXJyeTsKCQlhc3NlcnQoYS0+c2l6ZSA8PSBhLT5jYXBhY2l0eSk7Cgl9Cn0KCnZvaWQgcHJpbnQoY29uc3QgY2hhciogZmlsZW5hbWUsIGNvbnN0IEkqIGEpIHsKCWNoYXIgZm9ybWF0WzEwXTsKCXNpemVfdCBzOwoJRklMRSogZnA7CgoJYXNzZXJ0KGEtPmRhdGEgIT0gTlVMTCk7Cglhc3NlcnQoYS0+c2l6ZSA+IDApOwoJYXNzZXJ0KGEtPnNpemUgPD0gYS0+Y2FwYWNpdHkpOwoKCWZwID0gZm9wZW4oZmlsZW5hbWUsICJ3Iik7CgoJc3ByaW50Zihmb3JtYXQsICIlJTAlZHUiLCBGSUcpOwoKCXMgPSBhLT5zaXplOwoJZnByaW50ZihmcCwgIiV1IiwgYS0+ZGF0YVstLXNdKTsKCXdoaWxlIChzICE9IDApIHsKCQlmcHJpbnRmKGZwLCBmb3JtYXQsIGEtPmRhdGFbLS1zXSk7Cgl9CglmY2xvc2UoZnApOwp9CgppbnQgczJwKHNpemVfdCBzMSwgc2l6ZV90IHMyKSB7CglpbnQgaTsKCWZvciAoaSA9IDE7IGkgPCA2NDsgaSsrKSB7CgkJaWYgKCgoc2l6ZV90KTEgPDwgaSkgKyAxID49IHMxICsgczIpIHsKCQkJYnJlYWs7CgkJfQoJfQoJcmV0dXJuIGk7Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyKiogYXJndikgewoJaW50IG4gPSAzNDsKCUkgYTsKCUYgeDsKCglpbnQgcCA9IHMycCgoMWxsdSA8PCBuKSAqIGxvZygyKSAvIGxvZygxMCkgLyBGSUcgKyAxLCAxKTsKCXNpemVfdCBjYXAgPSAoc2l6ZV90KTEgPDwgcDsKCWFsbG9jX2koJmEsIGNhcCk7CglhbGxvY19mKCZ4LCBwKTsKCglhLmRhdGFbMF0gPSAxOwoJYS5zaXplID0gMTsKCglmb3IgKGludCBpID0gMDsgaSA8IG47IGkrKykgewoKCQlpbnQgcCA9IHMycChhLnNpemUsIGEuc2l6ZSk7CgkJaTJmKCZ4LCAmYSwgcCk7CgkJbXVsX2YyaSgmYSwgJngsICZ4LCAmeCk7CgkJYWRkX2koJmEsICZhLCAmYSk7CgoJCXsKCQkJY2hhciBmaWxlbmFtZVsyMDBdOwoJCQlzcHJpbnRmKGZpbGVuYW1lLCAiJWQudHh0IiwgaSsxKTsKCQkJcHJpbnQoZmlsZW5hbWUsICZhKTsKCQl9CgkJcHJpbnRmKCIlZCAlZlxuIiwgaSArIDEsIGVycl9tYXgpOwoJfQoKCWZyZWVfaSgmYSk7CglmcmVlX2YoJngpOwoJcmV0dXJuIDA7Cn0K