// Cordic.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <math.h>
/* working with IEEE doubles, means there are 53 bits
* of mantissa
*/
#define MAXBITS 53
/* define this to perform all (non 2power) multiplications
* and divisions with the cordic linear method.
*/
#define CORDIC_LINEARx
/* these are the constants needed */
static double invGain1;
static double invGain2;
static double atanTable[MAXBITS];
static double atanhTable[MAXBITS];
static double gain1Cordic();
static double gain2Cordic();
void initCordic()
{
/* must call this first to initialise the constants.
* of course, here i use the maths library, but the
* values would be precomputed.
*/
double t = 1;
int i;
for (i = 0; i < MAXBITS; ++i) {
atanTable[i] = atan(t);
t /= 2;
atanhTable[i] = 0.5*log((1+t)/(1-t));
}
/* set constants */
invGain1 = 1/gain1Cordic();
invGain2 = 1/gain2Cordic();
}
void cordit1(double* x0, double* y0, double* z0, double vecmode)
{
/* this is the circular method.
* one slight change from the other methods is the y < vecmode
* test. this is to implement arcsin, otherwise it can be
* y < 0 and you can compute arcsin from arctan using
* trig identities, so its not essential.
*/
double t;
double x, y, z;
int i;
t = 1;
x = *x0; y = *y0; z = *z0;
for (i = 0; i < MAXBITS; ++i) {
double x1;
if (vecmode >= 0 && y < vecmode || vecmode<0 && z >= 0) {
x1 = x - y*t;
y = y + x*t;
z = z - atanTable[i];
}
else {
x1 = x + y*t;
y = y - x*t;
z = z + atanTable[i];
}
x = x1;
t /= 2;
}
*x0 = x;
*y0 = y;
*z0 = z;
}
void cordit2(double* x0, double* y0, double* z0, double vecmode)
{
/* here's the hyperbolic methods. its very similar to
* the circular methods, but with some small differences.
*
* the `x' iteration have the opposite sign.
* iterations 4, 7, .. 3k+1 are repeated.
* iteration 0 is not performed.
*/
double t;
double x, y, z;
int i;
t = 0.5;
x = *x0; y = *y0; z = *z0;
int k = 3;
for (i = 0; i < MAXBITS; ++i) {
double x1;
int j;
for (j = 0; j < 2; ++j) {
if (vecmode >= 0 && y < 0 || vecmode<0 && z >= 0) {
x1 = x + y*t;
y = y + x*t;
z = z - atanhTable[i];
}
else {
x1 = x - y*t;
y = y - x*t;
z = z + atanhTable[i];
}
x = x1;
if (k) {
--k;
break;
}
else k = 3;
}
t /= 2;
}
*x0 = x;
*y0 = y;
*z0 = z;
}
void cordit0(double* x0, double* y0, double* z0, double vecmode)
{
/* the linear methods is the same as the circular but
* ive simplified out the x iteration as it doesnt change.
*/
double t;
double x, y, z;
int i;
t = 1;
x = *x0; y = *y0; z = *z0;
for (i = 0; i < MAXBITS; ++i) {
if (vecmode >= 0 && y < 0 || vecmode<0 && z >= 0) {
y = y + x*t;
z = z - t;
}
else {
y = y - x*t;
z = z + t;
}
t /= 2;
}
*x0 = x;
*y0 = y;
*z0 = z;
}
/** Linear features ***********************************************/
double mulCordic(double a, double b)
{
double x, y, z;
x = a;
y = 0;
z = b;
cordit0(&x, &y, &z, -1);
return y;
}
double divCordic(double a, double b)
{
double x, y, z;
x = b;
y = a;
z = 0;
cordit0(&x, &y, &z, 0);
return z;
}
#ifdef CORDIC_LINEAR
#define MULT(_a, _b) mulCordic(_a, _b)
#define DIVD(_a, _b) divCordic(_a, _b)
#else
#define MULT(_a, _b) (_a)*(_b)
#define DIVD(_a, _b) (_a)/(_b)
#endif
/** circular features ***********************************************/
static double gain1Cordic()
{
/* compute gain by evaluating cos(0) without inv gain */
double x, y, z;
x = 1;
y = 0;
z = 0;
cordit1(&x, &y, &z, -1);
return x;
}
double atanCordic(double a)
{
/* domain: all a */
double x = 1;
double z = 0;
cordit1(&x, &a, &z, 0);
return z;
}
double sincosCordic(double a, double* cosp)
{
/* |a| < 1.74 */
double sinp = 0;
*cosp = invGain1;
cordit1(cosp, &sinp, &a, -1);
return sinp;
}
double tanCordic(double a)
{
/* |a| < 1.74 */
double sinp = 0;
double cosp = invGain1;
cordit1(&cosp, &sinp, &a, -1);
return DIVD(sinp, cosp);
}
double asinCordic(double a)
{
/* |a| < 0.98 */
double x, y, z;
x = invGain1;
y = 0;
z = 0;
int neg = 1;
if (a < 0) {
a = -a;
neg = 0;
}
cordit1(&x, &y, &z, a);
if (neg) z = -z;
return z;
}
/** hyperbolic features ********************************************/
double gain2Cordic()
{
/* calculate hyperbolic gain */
double x, y, z;
x = 1;
y = 0;
z = 0;
cordit2(&x, &y, &z, -1);
return x;
}
double sinhcoshCordic(double a, double* coshp)
{
/* |a| < 1.13 */
double y;
*coshp = invGain2;
y = 0;
cordit2(coshp, &y, &a, -1);
return y;
}
double tanhCordic(double a)
{
/* |a| < 1.13 */
double sinhp, coshp;
coshp = invGain2;
sinhp = 0;
cordit2(&coshp, &sinhp, &a, -1);
return DIVD(sinhp,coshp);
}
double atanhCordic(double a)
{
/* |a| < 1.13 */
double x, z;
x = 1;
z = 0;
cordit2(&x, &a, &z, 0);
return z;
}
double logCordic(double a)
{
/* 0.1 < a < 9.58 */
double x, y, z;
x = a + 1;
y = a - 1;
z = 0;
cordit2(&x, &y, &z, 0);
return 2*z;
}
double sqrtCordic(double a)
{
/* 0.03 < a < 2 */
double x, y, z;
x = a + 0.25;
y = a - 0.25;
z = 0;
cordit2(&x, &y, &z, 0);
return MULT(x, invGain2);
}
double expCordic(double a)
{
double sinhp, coshp;
coshp = invGain2;
sinhp = 0;
cordit2(&coshp, &sinhp, &a, -1);
return sinhp + coshp;
}
double asinCordic1 (double a)
{
return 2.0 * atanCordic(a) * a / (1.0 + sqrt(1.0 - a*a));
}
int main()
{
/* just run a few tests */
double v;
double x;
double c;
initCordic();
x = 1;
v = atanCordic(x);
printf("atan %f = %.18e\n", x, v);
x = 1;
v = sincosCordic(x, &c);
printf("sin %f = %.18e\n", x, v);
printf("cos %f = %.18e\n", x, c);
x = 1;
v = tanCordic(x);
printf("tan %f = %.18e\n", x, v);
x = 0.5;
v = asinCordic(x);
printf("asin %f = %.18e\n", x, v);
x = 0.999999;
v = asinCordic(x);
printf("asin %f = %.18e\n", x, v);
v = asinCordic1(x);
printf("asin %f = %.18e\n", x, v);
x = 0.61;
v = asinCordic(x);
printf("asin %f = %.18e\n", x, v);
v = asinCordic1(x);
printf("asin %f = %.18e\n", x, v);
x = 0.65;
v = asinCordic(x);
printf("asin %f = %.18e\n", x, v);
v = asinCordic1(x);
printf("asin %f = %.18e\n", x, v);
x = 1;
v = sinhcoshCordic(x, &c);
printf("sinh %f = %.18e\n", x, v);
printf("cosh %f = %.18e\n", x, c);
x = 1;
v = tanhCordic(x);
printf("tanhh %f = %.18e\n", x, v);
x = 0.5;
v = atanhCordic(x);
printf("atanh %f = %.18e\n", x, v);
x = 0.8;
v = logCordic(x);
printf("log %f = %.18e\n", x, v);
x = 2;
v = sqrtCordic(x);
printf("sqrt %f = %.18e\n", x, v);
x = 1;
v = expCordic(x);
printf("exp %f = %.18e\n", x, v);
return 0;
}
Ly8gQ29yZGljLmNwcCA6IERlZmluZXMgdGhlIGVudHJ5IHBvaW50IGZvciB0aGUgY29uc29sZSBhcHBsaWNhdGlvbi4KLy8KCgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPG1hdGguaD4KCi8qIHdvcmtpbmcgd2l0aCBJRUVFIGRvdWJsZXMsIG1lYW5zIHRoZXJlIGFyZSA1MyBiaXRzCiAqIG9mIG1hbnRpc3NhCiAqLwojZGVmaW5lIE1BWEJJVFMgICAgICAgICA1MwovKiBkZWZpbmUgdGhpcyB0byBwZXJmb3JtIGFsbCAobm9uIDJwb3dlcikgbXVsdGlwbGljYXRpb25zCiAqIGFuZCBkaXZpc2lvbnMgd2l0aCB0aGUgY29yZGljIGxpbmVhciBtZXRob2QuCiAqLwojZGVmaW5lIENPUkRJQ19MSU5FQVJ4Ci8qIHRoZXNlIGFyZSB0aGUgY29uc3RhbnRzIG5lZWRlZCAqLwpzdGF0aWMgZG91YmxlIGludkdhaW4xOwpzdGF0aWMgZG91YmxlIGludkdhaW4yOwpzdGF0aWMgZG91YmxlIGF0YW5UYWJsZVtNQVhCSVRTXTsKc3RhdGljIGRvdWJsZSBhdGFuaFRhYmxlW01BWEJJVFNdOwpzdGF0aWMgZG91YmxlIGdhaW4xQ29yZGljKCk7CnN0YXRpYyBkb3VibGUgZ2FpbjJDb3JkaWMoKTsKdm9pZCBpbml0Q29yZGljKCkKewogICAgLyogbXVzdCBjYWxsIHRoaXMgZmlyc3QgdG8gaW5pdGlhbGlzZSB0aGUgY29uc3RhbnRzLgogICAgICogb2YgY291cnNlLCBoZXJlIGkgdXNlIHRoZSBtYXRocyBsaWJyYXJ5LCBidXQgdGhlCiAgICAgKiB2YWx1ZXMgd291bGQgYmUgcHJlY29tcHV0ZWQuCiAgICAgKi8KICAgIGRvdWJsZSB0ID0gMTsKICAgIGludCBpOwogICAgZm9yIChpID0gMDsgaSA8IE1BWEJJVFM7ICsraSkgewogICAgICAgIGF0YW5UYWJsZVtpXSA9IGF0YW4odCk7CiAgICAgICAgdCAvPSAyOwogICAgICAgIGF0YW5oVGFibGVbaV0gPSAwLjUqbG9nKCgxK3QpLygxLXQpKTsKICAgIH0KICAgIC8qIHNldCBjb25zdGFudHMgKi8KICAgIGludkdhaW4xID0gMS9nYWluMUNvcmRpYygpOwogICAgaW52R2FpbjIgPSAxL2dhaW4yQ29yZGljKCk7Cn0Kdm9pZCBjb3JkaXQxKGRvdWJsZSogeDAsIGRvdWJsZSogeTAsIGRvdWJsZSogejAsIGRvdWJsZSB2ZWNtb2RlKQp7CiAgICAvKiB0aGlzIGlzIHRoZSBjaXJjdWxhciBtZXRob2QuIAogICAgICogb25lIHNsaWdodCBjaGFuZ2UgZnJvbSB0aGUgb3RoZXIgbWV0aG9kcyBpcyB0aGUgeSA8IHZlY21vZGUgCiAgICAgKiB0ZXN0LiB0aGlzIGlzIHRvIGltcGxlbWVudCBhcmNzaW4sIG90aGVyd2lzZSBpdCBjYW4gYmUKICAgICAqIHkgPCAwIGFuZCB5b3UgY2FuIGNvbXB1dGUgYXJjc2luIGZyb20gYXJjdGFuIHVzaW5nCiAgICAgKiB0cmlnIGlkZW50aXRpZXMsIHNvIGl0cyBub3QgZXNzZW50aWFsLgogICAgICovCiAgICBkb3VibGUgdDsKICAgIGRvdWJsZSB4LCB5LCB6OwogICAgaW50IGk7CiAgICB0ID0gMTsKICAgIHggPSAqeDA7IHkgPSAqeTA7IHogPSAqejA7CiAgICBmb3IgKGkgPSAwOyBpIDwgTUFYQklUUzsgKytpKSB7CiAgICAgICAgZG91YmxlIHgxOwogICAgICAgIGlmICh2ZWNtb2RlID49IDAgJiYgeSA8IHZlY21vZGUgfHwgdmVjbW9kZTwwICAmJiB6ID49IDApIHsKICAgICAgICAgICAgeDEgPSB4IC0geSp0OwogICAgICAgICAgICB5ID0geSArIHgqdDsKICAgICAgICAgICAgeiA9IHogLSBhdGFuVGFibGVbaV07CiAgICAgICAgfQogICAgICAgIGVsc2UgewogICAgICAgICAgICB4MSA9IHggKyB5KnQ7CiAgICAgICAgICAgIHkgPSB5IC0geCp0OwogICAgICAgICAgICB6ID0geiArIGF0YW5UYWJsZVtpXTsKICAgICAgICB9CiAgICAgICAgeCA9IHgxOwogICAgICAgIHQgLz0gMjsKICAgIH0KICAgICp4MCA9IHg7CiAgICAqeTAgPSB5OwogICAgKnowID0gejsKfQp2b2lkIGNvcmRpdDIoZG91YmxlKiB4MCwgZG91YmxlKiB5MCwgZG91YmxlKiB6MCwgZG91YmxlIHZlY21vZGUpCnsKICAgIC8qIGhlcmUncyB0aGUgaHlwZXJib2xpYyBtZXRob2RzLiBpdHMgdmVyeSBzaW1pbGFyIHRvCiAgICAgKiB0aGUgY2lyY3VsYXIgbWV0aG9kcywgYnV0IHdpdGggc29tZSBzbWFsbCBkaWZmZXJlbmNlcy4KICAgICAqCiAgICAgKiB0aGUgYHgnIGl0ZXJhdGlvbiBoYXZlIHRoZSBvcHBvc2l0ZSBzaWduLgogICAgICogaXRlcmF0aW9ucyA0LCA3LCAuLiAzaysxIGFyZSByZXBlYXRlZC4KICAgICAqIGl0ZXJhdGlvbiAwIGlzIG5vdCBwZXJmb3JtZWQuCiAgICAgKi8KICAgIGRvdWJsZSB0OwogICAgZG91YmxlIHgsIHksIHo7CiAgICBpbnQgaTsKICAgIHQgPSAwLjU7CiAgICB4ID0gKngwOyB5ID0gKnkwOyB6ID0gKnowOwogICAgaW50IGsgPSAzOwogICAgZm9yIChpID0gMDsgaSA8IE1BWEJJVFM7ICsraSkgewogICAgICAgIGRvdWJsZSB4MTsKICAgICAgICBpbnQgajsKICAgICAgICBmb3IgKGogPSAwOyBqIDwgMjsgKytqKSB7CiAgICAgICAgICAgIGlmICh2ZWNtb2RlID49IDAgJiYgeSA8IDAgfHwgdmVjbW9kZTwwICAmJiB6ID49IDApIHsKICAgICAgICAgICAgICAgIHgxID0geCArIHkqdDsKICAgICAgICAgICAgICAgIHkgPSB5ICsgeCp0OwogICAgICAgICAgICAgICAgeiA9IHogLSBhdGFuaFRhYmxlW2ldOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgeDEgPSB4IC0geSp0OwogICAgICAgICAgICAgICAgeSA9IHkgLSB4KnQ7CiAgICAgICAgICAgICAgICB6ID0geiArIGF0YW5oVGFibGVbaV07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgeCA9IHgxOwogICAgICAgICAgICBpZiAoaykgewogICAgICAgICAgICAgICAgLS1rOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSBrID0gMzsKICAgICAgICB9CiAgICAgICAgdCAvPSAyOwogICAgfQogICAgKngwID0geDsKICAgICp5MCA9IHk7CiAgICAqejAgPSB6Owp9CnZvaWQgY29yZGl0MChkb3VibGUqIHgwLCBkb3VibGUqIHkwLCBkb3VibGUqIHowLCBkb3VibGUgdmVjbW9kZSkKewogICAgLyogdGhlIGxpbmVhciBtZXRob2RzIGlzIHRoZSBzYW1lIGFzIHRoZSBjaXJjdWxhciBidXQKICAgICAqIGl2ZSBzaW1wbGlmaWVkIG91dCB0aGUgeCBpdGVyYXRpb24gYXMgaXQgZG9lc250IGNoYW5nZS4KICAgICAqLwogICAgZG91YmxlIHQ7CiAgICBkb3VibGUgeCwgeSwgejsKICAgIGludCBpOwogICAgdCA9IDE7CiAgICB4ID0gKngwOyB5ID0gKnkwOyB6ID0gKnowOwogICAgZm9yIChpID0gMDsgaSA8IE1BWEJJVFM7ICsraSkgewogICAgICAgIGlmICh2ZWNtb2RlID49IDAgJiYgeSA8IDAgfHwgdmVjbW9kZTwwICAmJiB6ID49IDApIHsKICAgICAgICAgICAgeSA9IHkgKyB4KnQ7CiAgICAgICAgICAgIHogPSB6IC0gdDsKICAgICAgICB9CiAgICAgICAgZWxzZSB7CiAgICAgICAgICAgIHkgPSB5IC0geCp0OwogICAgICAgICAgICB6ID0geiArIHQ7CiAgICAgICAgfQogICAgICAgIHQgLz0gMjsKICAgIH0KICAgICp4MCA9IHg7CiAgICAqeTAgPSB5OwogICAgKnowID0gejsKfQovKiogTGluZWFyIGZlYXR1cmVzICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwpkb3VibGUgbXVsQ29yZGljKGRvdWJsZSBhLCBkb3VibGUgYikKewogICAgZG91YmxlIHgsIHksIHo7CiAgICB4ID0gYTsKICAgIHkgPSAwOwogICAgeiA9IGI7CiAgICBjb3JkaXQwKCZ4LCAmeSwgJnosIC0xKTsKICAgIHJldHVybiB5Owp9CmRvdWJsZSBkaXZDb3JkaWMoZG91YmxlIGEsIGRvdWJsZSBiKQp7CiAgICBkb3VibGUgeCwgeSwgejsKICAgIHggPSBiOwogICAgeSA9IGE7CiAgICB6ID0gMDsKICAgIGNvcmRpdDAoJngsICZ5LCAmeiwgMCk7CiAgICByZXR1cm4gejsKfQojaWZkZWYgQ09SRElDX0xJTkVBUgojZGVmaW5lIE1VTFQoX2EsIF9iKSAgICBtdWxDb3JkaWMoX2EsIF9iKQojZGVmaW5lIERJVkQoX2EsIF9iKSAgICBkaXZDb3JkaWMoX2EsIF9iKQojZWxzZQojZGVmaW5lIE1VTFQoX2EsIF9iKSAgICAoX2EpKihfYikKI2RlZmluZSBESVZEKF9hLCBfYikgICAgKF9hKS8oX2IpCiNlbmRpZiAKLyoqIGNpcmN1bGFyIGZlYXR1cmVzICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwpzdGF0aWMgZG91YmxlIGdhaW4xQ29yZGljKCkKewogICAgLyogY29tcHV0ZSBnYWluIGJ5IGV2YWx1YXRpbmcgY29zKDApIHdpdGhvdXQgaW52IGdhaW4gKi8KICAgIGRvdWJsZSB4LCB5LCB6OwogICAgeCA9IDE7CiAgICB5ID0gMDsKICAgIHogPSAwOwogICAgY29yZGl0MSgmeCwgJnksICZ6LCAtMSk7CiAgICByZXR1cm4geDsKfQpkb3VibGUgYXRhbkNvcmRpYyhkb3VibGUgYSkKewogICAgLyogZG9tYWluOiBhbGwgYSAqLwogICAgZG91YmxlIHggPSAxOwogICAgZG91YmxlIHogPSAwOwogICAgY29yZGl0MSgmeCwgJmEsICZ6LCAwKTsKICAgIHJldHVybiB6Owp9CmRvdWJsZSBzaW5jb3NDb3JkaWMoZG91YmxlIGEsIGRvdWJsZSogY29zcCkKewogICAgLyogfGF8IDwgMS43NCAqLwogICAgZG91YmxlIHNpbnAgPSAwOwogICAgKmNvc3AgPSBpbnZHYWluMTsKICAgIGNvcmRpdDEoY29zcCwgJnNpbnAsICZhLCAtMSk7CiAgICByZXR1cm4gc2lucDsKfQpkb3VibGUgdGFuQ29yZGljKGRvdWJsZSBhKQp7CiAgICAvKiB8YXwgPCAxLjc0ICovCiAgICBkb3VibGUgc2lucCA9IDA7CiAgICBkb3VibGUgY29zcCA9IGludkdhaW4xOwogICAgY29yZGl0MSgmY29zcCwgJnNpbnAsICZhLCAtMSk7CiAgICByZXR1cm4gRElWRChzaW5wLCBjb3NwKTsKfQpkb3VibGUgYXNpbkNvcmRpYyhkb3VibGUgYSkKewogICAgLyogfGF8IDwgMC45OCAqLwogICAgZG91YmxlIHgsIHksIHo7CiAgICAKICAgIHggPSBpbnZHYWluMTsKICAgIHkgPSAwOwogICAgeiA9IDA7CiAgICBpbnQgbmVnID0gMTsKICAgIGlmIChhIDwgMCkgewogICAgICAgIGEgPSAtYTsKICAgICAgICBuZWcgPSAwOwogICAgfQogICAgICAgIAogICAgY29yZGl0MSgmeCwgJnksICZ6LCBhKTsKICAgIGlmIChuZWcpIHogPSAtejsKICAgIHJldHVybiB6Owp9Ci8qKiBoeXBlcmJvbGljIGZlYXR1cmVzICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwpkb3VibGUgZ2FpbjJDb3JkaWMoKQp7CiAgICAvKiBjYWxjdWxhdGUgaHlwZXJib2xpYyBnYWluICovCiAgICBkb3VibGUgeCwgeSwgejsKICAgIHggPSAxOwogICAgeSA9IDA7CiAgICB6ID0gMDsKICAgIGNvcmRpdDIoJngsICZ5LCAmeiwgLTEpOwogICAgcmV0dXJuIHg7Cn0KZG91YmxlIHNpbmhjb3NoQ29yZGljKGRvdWJsZSBhLCBkb3VibGUqIGNvc2hwKQp7CiAgICAvKiB8YXwgPCAxLjEzICovCiAgICBkb3VibGUgeTsKICAgICpjb3NocCA9IGludkdhaW4yOwogICAgeSA9IDA7CiAgICBjb3JkaXQyKGNvc2hwLCAmeSwgJmEsIC0xKTsKICAgIHJldHVybiB5Owp9CmRvdWJsZSB0YW5oQ29yZGljKGRvdWJsZSBhKQp7CiAgICAvKiB8YXwgPCAxLjEzICovCiAgIGRvdWJsZSBzaW5ocCwgY29zaHA7CiAgIGNvc2hwID0gaW52R2FpbjI7CiAgIHNpbmhwID0gMDsKICAgY29yZGl0MigmY29zaHAsICZzaW5ocCwgJmEsIC0xKTsKICAgcmV0dXJuIERJVkQoc2luaHAsY29zaHApOwp9CmRvdWJsZSBhdGFuaENvcmRpYyhkb3VibGUgYSkKewogICAgLyogfGF8IDwgMS4xMyAqLwogICAgZG91YmxlIHgsIHo7CiAgICB4ID0gMTsKICAgIHogPSAwOwogICAgY29yZGl0MigmeCwgJmEsICZ6LCAwKTsKICAgIHJldHVybiB6Owp9CmRvdWJsZSBsb2dDb3JkaWMoZG91YmxlIGEpCnsKICAgIC8qIDAuMSA8IGEgPCA5LjU4ICovCiAgICBkb3VibGUgeCwgeSwgejsKICAgIHggPSBhICsgMTsKICAgIHkgPSBhIC0gMTsKICAgIHogPSAwOwogICAgY29yZGl0MigmeCwgJnksICZ6LCAwKTsKICAgIHJldHVybiAyKno7Cn0KZG91YmxlIHNxcnRDb3JkaWMoZG91YmxlIGEpCnsKICAgIC8qIDAuMDMgPCBhIDwgMiAqLwogICAgZG91YmxlIHgsIHksIHo7CiAgICB4ID0gYSArIDAuMjU7CiAgICB5ID0gYSAtIDAuMjU7CiAgICB6ID0gMDsKICAgIGNvcmRpdDIoJngsICZ5LCAmeiwgMCk7CiAgICByZXR1cm4gTVVMVCh4LCBpbnZHYWluMik7Cn0KZG91YmxlIGV4cENvcmRpYyhkb3VibGUgYSkKewogICAgZG91YmxlIHNpbmhwLCBjb3NocDsKICAgIGNvc2hwID0gaW52R2FpbjI7CiAgICBzaW5ocCA9IDA7CiAgICBjb3JkaXQyKCZjb3NocCwgJnNpbmhwLCAmYSwgLTEpOwogICAgcmV0dXJuIHNpbmhwICsgY29zaHA7Cn0KCmRvdWJsZSBhc2luQ29yZGljMSAoZG91YmxlIGEpCnsKCXJldHVybiAyLjAgKiBhdGFuQ29yZGljKGEpICogYSAvICgxLjAgKyBzcXJ0KDEuMCAtIGEqYSkpOwp9CgppbnQgbWFpbigpCnsKICAgIC8qIGp1c3QgcnVuIGEgZmV3IHRlc3RzICovCiAgICBkb3VibGUgdjsKICAgIGRvdWJsZSB4OwogICAgZG91YmxlIGM7CiAgICBpbml0Q29yZGljKCk7CiAgICB4ID0gMTsKICAgIHYgPSBhdGFuQ29yZGljKHgpOwogICAgcHJpbnRmKCJhdGFuICVmID0gJS4xOGVcbiIsIHgsIHYpOwogICAgeCA9IDE7CiAgICB2ID0gc2luY29zQ29yZGljKHgsICZjKTsKICAgIHByaW50Zigic2luICVmID0gJS4xOGVcbiIsIHgsIHYpOwogICAgcHJpbnRmKCJjb3MgJWYgPSAlLjE4ZVxuIiwgeCwgYyk7CiAgICB4ID0gMTsKICAgIHYgPSB0YW5Db3JkaWMoeCk7CiAgICBwcmludGYoInRhbiAlZiA9ICUuMThlXG4iLCB4LCB2KTsKICAgIHggPSAwLjU7CiAgICB2ID0gYXNpbkNvcmRpYyh4KTsKICAgIHByaW50ZigiYXNpbiAlZiA9ICUuMThlXG4iLCB4LCB2KTsKCXggPSAwLjk5OTk5OTsKICAgIHYgPSBhc2luQ29yZGljKHgpOwogICAgcHJpbnRmKCJhc2luICVmID0gJS4xOGVcbiIsIHgsIHYpOwoJdiA9IGFzaW5Db3JkaWMxKHgpOwogICAgcHJpbnRmKCJhc2luICVmID0gJS4xOGVcbiIsIHgsIHYpOwoJeCA9IDAuNjE7CiAgICB2ID0gYXNpbkNvcmRpYyh4KTsKICAgIHByaW50ZigiYXNpbiAlZiA9ICUuMThlXG4iLCB4LCB2KTsKCXYgPSBhc2luQ29yZGljMSh4KTsKICAgIHByaW50ZigiYXNpbiAlZiA9ICUuMThlXG4iLCB4LCB2KTsKCXggPSAwLjY1OwogICAgdiA9IGFzaW5Db3JkaWMoeCk7CiAgICBwcmludGYoImFzaW4gJWYgPSAlLjE4ZVxuIiwgeCwgdik7Cgl2ID0gYXNpbkNvcmRpYzEoeCk7CiAgICBwcmludGYoImFzaW4gJWYgPSAlLjE4ZVxuIiwgeCwgdik7CiAgICB4ID0gMTsKICAgIHYgPSBzaW5oY29zaENvcmRpYyh4LCAmYyk7CiAgICBwcmludGYoInNpbmggJWYgPSAlLjE4ZVxuIiwgeCwgdik7CiAgICBwcmludGYoImNvc2ggJWYgPSAlLjE4ZVxuIiwgeCwgYyk7CiAgICB4ID0gMTsKICAgIHYgPSB0YW5oQ29yZGljKHgpOwogICAgcHJpbnRmKCJ0YW5oaCAlZiA9ICUuMThlXG4iLCB4LCB2KTsKICAgIHggPSAwLjU7CiAgICB2ID0gYXRhbmhDb3JkaWMoeCk7CiAgICBwcmludGYoImF0YW5oICVmID0gJS4xOGVcbiIsIHgsIHYpOwogICAgeCA9IDAuODsKICAgIHYgPSBsb2dDb3JkaWMoeCk7CiAgICBwcmludGYoImxvZyAlZiA9ICUuMThlXG4iLCB4LCB2KTsKICAgIHggPSAyOwogICAgdiA9IHNxcnRDb3JkaWMoeCk7CiAgICBwcmludGYoInNxcnQgJWYgPSAlLjE4ZVxuIiwgeCwgdik7CiAgICB4ID0gMTsKICAgIHYgPSBleHBDb3JkaWMoeCk7CiAgICBwcmludGYoImV4cCAlZiA9ICUuMThlXG4iLCB4LCB2KTsKCiAgICByZXR1cm4gMDsKfQo=