Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 Aug 2012 02:57:27 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Stephen Montgomery-Smith <stephen@missouri.edu>
Cc:        freebsd-numerics@FreeBSD.org
Subject:   Re: Complex arg-trig functions
Message-ID:  <20120814003614.H3692@besplex.bde.org>
In-Reply-To: <5027F07E.9060409@missouri.edu>
References:  <5017111E.6060003@missouri.edu> <501C361D.4010807@missouri.edu> <20120804165555.X1231@besplex.bde.org> <501D51D7.1020101@missouri.edu> <20120805030609.R3101@besplex.bde.org> <501D9C36.2040207@missouri.edu> <20120805175106.X3574@besplex.bde.org> <501EC015.3000808@missouri.edu> <20120805191954.GA50379@troutmask.apl.washington.edu> <20120807205725.GA10572@server.rulingia.com> <20120809025220.N4114@besplex.bde.org> <5027F07E.9060409@missouri.edu>

next in thread | previous in thread | raw e-mail | index | archive | help
  This message is in MIME format.  The first part should be readable text,
  while the remaining parts are likely unreadable without MIME-aware tools.

--0-1116022701-1344877047=:3692
Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed

On Sun, 12 Aug 2012, Stephen Montgomery-Smith wrote:

> Having brooded over the code for too many weeks, I now think I have finished 
> my complex arg-trig functions.  I have also written versions for float and 
> long.  So I am ready to have the code reviewed.
>
> http://people.freebsd.org/~stephen/

I finally tested a version of this.  I only did simple comparisons (float
vs double and double vs long double).  The results look promising after
fixing a few bugs:

% amd64 float prec, on 2**12 * 2**12 args:
% rcacos:max_er = 0x58460841 2.7585, avg_er = 0.317, #>=1:0.5 = 29084:255712
% rcacosh:max_er = 0x5e1e45e6 2.9412, avg_er = 0.262, #>=1:0.5 = 85868:3413684
% rcasin:max_er = 0x631b8183 3.0971, avg_er = 0.209, #>=1:0.5 = 38388:382508
% rcasinh:max_er = 0x5e1e45e6 2.9412, avg_er = 0.262, #>=1:0.5 = 85868:3413684
% rcatan:max_er = 0x51d7c47a 2.5576, avg_er = 0.290, #>=1:0.5 = 52984:318084
% rcatanh:max_er = 0x3693fccd4f 436.6246, avg_er = 0.223, #>=1:0.5 = 213124:1438280
% rclog: max_er = 0x26dfae4d 1.2148, avg_er = 0.247, #>=1:0.5 = 184:92244
% icacos:max_er = 0x5e1e45e6 2.9412, avg_er = 0.262, #>=1:0.5 = 85868:3413684
% icacosh:max_er = 0x3690000000 436.5000, avg_er = 0.317, #>=1:0.5 = 29104:255732
% icasin:max_er = 0x5e1e45e6 2.9412, avg_er = 0.262, #>=1:0.5 = 85868:3413684
% icasinh:max_er = 0x631b8183 3.0971, avg_er = 0.209, #>=1:0.5 = 38388:382508
% icatan:max_er = 0x3693fccd4f 436.6246, avg_er = 0.223, #>=1:0.5 = 213124:1438280
% icatanh:max_er = 0x51d7c47a 2.5576, avg_er = 0.290, #>=1:0.5 = 52984:318084
% iclog: max_er = 0x1fc2b4f5 0.9925, avg_er = 0.302, #>=1:0.5 = 0:349830
% 
% amd64 double prec, on 2**12 x 2**12 args:
% rcacos:max_er =     0x1b5a 3.4189, avg_er = 0.228, #>=1:0.5 = 2394:125988
% rcacosh:max_er =      0xf7d 1.9360, avg_er = 0.257, #>=1:0.5 = 612:2741860
% rcasin:max_er =     0x15c5 2.7212, avg_er = 0.113, #>=1:0.5 = 33296:99152
% rcasinh:max_er =      0xf7d 1.9360, avg_er = 0.257, #>=1:0.5 = 612:2741796
% rcatan:max_er = 0x8000000000000000 4503599627370496.0000, avg_er = 268435456.212, #>=1:0.5 = 4681:81365
% rcatanh:max_er = 0x8000000000000000 4503599627370496.0000, avg_er = 268435456.047, #>=1:0.5 = 428997:691341
% rclog: max_er =      0x704 0.8770, avg_er = 0.250, #>=1:0.5 = 0:20152
% icacos:max_er =      0xf7d 1.9360, avg_er = 0.257, #>=1:0.5 = 612:2741860
% icacosh:max_er =     0x1b5a 3.4189, avg_er = 0.228, #>=1:0.5 = 2394:125988
% icasin:max_er =      0xf7d 1.9360, avg_er = 0.257, #>=1:0.5 = 612:2741796
% icasinh:max_er =     0x15c5 2.7212, avg_er = 0.113, #>=1:0.5 = 33296:99152
% icatan:max_er = 0x8000000000000000 4503599627370496.0000, avg_er = 268435456.047, #>=1:0.5 = 428997:691341
% icatanh:max_er = 0x8000000000000000 4503599627370496.0000, avg_er = 268435456.212, #>=1:0.5 = 4681:81365
% iclog: max_er =      0x6f4 0.8691, avg_er = 0.213, #>=1:0.5 = 0:181032

rfoo is the real part of foo, etc.

2**12 x 2**12 args is not enough.  Some bugs showed up only with slightly
more args, but after fixing some bugs the behaviour doesn't seem to
depend so much on the number.

The error of 436.6246 upls has been turning up a lot.  It was for a bug
in my test program for a result of 0 when the correctly rounded result is
the smallest denormal, but I thought I fixed it.

The error of 0x8000000000000000 for double precision *catan* is a sign
mismatch.

% i386 float prec, on 2**12 x 2**12 args:
% rcacos:max_er = 0x42cd19c6 2.0875, avg_er = 0.314, #>=1:0.5 = 3854:215116
% rcacosh:max_er = 0x3170e232 1.5450, avg_er = 0.254, #>=1:0.5 = 23008:3245028
% rcasin:max_er = 0x55adc0df 2.6775, avg_er = 0.208, #>=1:0.5 = 34304:353980
% rcasinh:max_er = 0x3170e232 1.5450, avg_er = 0.254, #>=1:0.5 = 23008:3245028
% rcatan:max_er = 0x3c4078ec 1.8829, avg_er = 0.284, #>=1:0.5 = 13260:190836
% rcatanh:max_er = 0x3693fccd4f 436.6246, avg_er = 0.186, #>=1:0.5 = 4796:421616
% rclog: max_er = 0x25830853 1.1722, avg_er = 0.246, #>=1:0.5 = 120:24892
% icacos:max_er = 0x3170e232 1.5450, avg_er = 0.254, #>=1:0.5 = 23008:3245028
% icacosh:max_er = 0x3690000000 436.5000, avg_er = 0.315, #>=1:0.5 = 3874:215136
% icasin:max_er = 0x3170e232 1.5450, avg_er = 0.254, #>=1:0.5 = 23008:3245028
% icasinh:max_er = 0x55adc0df 2.6775, avg_er = 0.208, #>=1:0.5 = 34304:353980
% icatan:max_er = 0x3693fccd4f 436.6246, avg_er = 0.186, #>=1:0.5 = 4796:421616
% icatanh:max_er = 0x3c4078ec 1.8829, avg_er = 0.284, #>=1:0.5 = 13260:190836
% iclog: max_er = 0x1fc2b4f5 0.9925, avg_er = 0.302, #>=1:0.5 = 0:338712
% 
% i386 double prec, on 2**12 x 2**12 args:
% rcacos:max_er =     0x11e8 2.2383, avg_er = 0.165, #>=1:0.5 = 248:111850
% rcacosh:max_er =      0xb02 1.3760, avg_er = 0.256, #>=1:0.5 = 104:2715312
% rcasin:max_er =     0x13ce 2.4756, avg_er = 0.112, #>=1:0.5 = 5616:95060
% rcasinh:max_er =      0xb02 1.3760, avg_er = 0.256, #>=1:0.5 = 104:2715312
% rcatan:max_er =      0x9ed 1.2407, avg_er = 0.015, #>=1:0.5 = 4084:48920
% rcatanh:max_er =      0xb17 1.3862, avg_er = 0.014, #>=1:0.5 = 56:77456
% rclog: max_er =      0x704 0.8770, avg_er = 0.250, #>=1:0.5 = 0:20112
% icacos:max_er =      0xb02 1.3760, avg_er = 0.256, #>=1:0.5 = 104:2715312
% icacosh:max_er =     0x11e8 2.2383, avg_er = 0.165, #>=1:0.5 = 248:111850
% icasin:max_er =      0xb02 1.3760, avg_er = 0.256, #>=1:0.5 = 104:2715312
% icasinh:max_er =     0x13ce 2.4756, avg_er = 0.112, #>=1:0.5 = 5616:95060
% icatan:max_er =      0xb17 1.3862, avg_er = 0.014, #>=1:0.5 = 56:77456
% icatanh:max_er =      0x9ed 1.2407, avg_er = 0.015, #>=1:0.5 = 4084:48920
% iclog: max_er =      0x6f4 0.8691, avg_er = 0.213, #>=1:0.5 = 0:181032

Note that i386 doesn't have the sign errors.  However, i386 with -O0 has
the sign errors for at least float precision in the same places that
amd64 with -O has them for double precision.

> The long versions require a logl and a log1pl, which I faked using mpfr.
>
> The float versions are more complicated, because FLT_EPSILON is too close to 
> the 4th root of FLT_MIN.  It is simpler to make the float versions wrappers 
> for the double versions.  But I wrote the float versions anyway, just in case 
> some purist insists that the wrapper approach is morally wrong.

There are negative reasons to have the float versions unless they are not
wrappers.  The reasons to have non-wrappers are to test the algorithm and
run faster.

Fixes needed for the above test results:

@ diff -c2 catrig.c~ catrig.c
@ *** catrig.c~	Sun Aug 12 17:29:18 2012
@ --- catrig.c	Mon Aug 13 12:07:09 2012
@ ***************
@ *** 265,269 ****
@   		return;
@   	}
@ ! 	if (y < MIN_4TH_ROOT) {
@   		/*
@   		 * Avoid a possible underflow caused by y/A.  For casinh this
@ --- 265,269 ----
@   		return;
@   	}
@ ! 	if (!ISNAN(x) && y < MIN_4TH_ROOT) {
@   		/*
@   		 * Avoid a possible underflow caused by y/A.  For casinh this

This stops the result for NaN x depending on the size of y relative
to MIN_4TH_ROOT.  MIN_4TH_ROOT varies with the precision, but the result
shouldn't vary with the precision.  The result should probably be the
original NaN x quieted (unless y is also NaN).  This happens naturally
if you do a computation with x (except -x).  However, symmetry often
requires forcing or flipping signs, and we force or flip the sign even
for NaNs.  This change gives consistent signs for NaN results, by taking
the same path in all precisions.

@ ***************
@ *** 408,416 ****
@ 
@   	if (ISFINITE(bx) && ISFINITE(by) && (x > RECIP_SQRT_EPSILON_100 || y > RECIP_SQRT_EPSILON_100)) {
@ ! 		if (huge+x+y>one) { /* raise inexact flag */
@ ! 			w = clog_for_large_values(z) + M_LN2;

Addition clobbers the sign of -0 in the imaginary part in some cases.
I think it should clobber it in all cases, since it does for non-complex
doubles (-0.0 + +0.0 is +0.0).  Clobbering was observed in the following
cases:
- on i386 (-march=athlon64) with -O0, presumably because the addition to
   the imaginary part was not optimized away then
- on amd64 with -O0 and -O, presumably because:
   - same as i386 for -O0
   - with -O (no -march), float complex and double complex are represented
     as a vector in an SSE2 register, and it is natural to add both the
     components of the vector, and this may be optimal for at least float
     complex with the default -march.  I didn't check what happens for
     double complex.

@   			if (sy == 0)
@ ! 				return (cpack(cimag(w), -creal(w)));
@ ! 			return (cpack(-cimag(w), creal(w)));

The sign of creal(cacos()) is always 1, but this makes it +- the sign
of atan2(x, y).

@   		}
@   	}
@ --- 408,420 ----
@ 
@   	if (ISFINITE(bx) && ISFINITE(by) && (x > RECIP_SQRT_EPSILON_100 || y > RECIP_SQRT_EPSILON_100)) {
@ ! 		/* XXX following can also raise overflow */

Just note this error.

@ ! 		if (huge+x+y>one) { /* raise inexact */

Start removing ' flag'.

@ ! 			w = clog_for_large_values(z);
@ ! 			/* Can't add M_LN2 to w since it should clobber -0*I. */
@ ! 			rx = fabs(cimag(w));
@ ! 			ry = creal(w) + M_LN2;
@   			if (sy == 0)
@ ! 				ry = -ry;
@ ! 			return (cpack(rx, ry));
@   		}
@   	}

Fix the above bugs.

@ ***************
@ *** 482,486 ****
@   	 * but this case should happen extremely rarely.
@   	 */
@ ! 	if (ay > 0.5*DBL_MAX)
@   		return (cpack(log(hypot(x / M_E, y / M_E)) + 1, atan2(y, x)));
@ 
@ --- 486,490 ----
@   	 * but this case should happen extremely rarely.
@   	 */
@ ! 	if (ax > 0.5*DBL_MAX)
@   		return (cpack(log(hypot(x / M_E, y / M_E)) + 1, atan2(y, x)));
@

The smallest of ax and ay must be compared.  I think I broke this in an
early version of clog().  Replacing the whole function by clog() made
little difference once this was fixed.

@ diff -c2 catrigf.c~ catrigf.c
@ *** catrigf.c~	Sun Aug 12 17:00:52 2012
@ --- catrigf.c	Mon Aug 13 14:14:42 2012
@ ***************
@ *** 138,142 ****
@   		return;
@   	}
@ ! 	if (y < MIN_4TH_ROOT) {
@   		*B_is_usable = 0;
@   		if ((int)y==0) /* raise inexact flag */
@ --- 138,142 ----
@   		return;
@   	}
@ ! 	if (!isnan(x) && y < MIN_4TH_ROOT) {
@   		*B_is_usable = 0;
@   		if ((int)y==0) /* raise inexact flag */
@ ***************
@ *** 233,240 ****
@   	if (isfinite(x) && isfinite(y) && (x > RECIP_SQRT_EPSILON_100 || y > RECIP_SQRT_EPSILON_100)) {
@   		if (huge+x+y>one) { /* raise inexact flag */
@ ! 			w = clog_for_large_values(z) + M_LN2;
@   			if (sy == 0)
@ ! 				return (cpackf(cimagf(w), -crealf(w)));
@ ! 			return (cpackf(-cimagf(w), crealf(w)));
@   		}
@   	}
@ --- 233,242 ----
@   	if (isfinite(x) && isfinite(y) && (x > RECIP_SQRT_EPSILON_100 || y > RECIP_SQRT_EPSILON_100)) {
@   		if (huge+x+y>one) { /* raise inexact flag */
@ ! 			w = clog_for_large_values(z);
@ ! 			rx = fabsf(cimagf(w));
@ ! 			ry = crealf(w) + M_LN2;
@   			if (sy == 0)
@ ! 				ry = -ry;
@ ! 			return (cpackf(rx, ry));
@   		}
@   	}
@ ***************
@ *** 290,294 ****
@   	}
@ 
@ ! 	if (ay > 0.5*FLT_MAX)
@   		return (cpackf(logf(hypotf(x / M_E, y / M_E)) + 1, atan2f(y, x)));
@ 
@ --- 292,296 ----
@   	}
@ 
@ ! 	if (ax > 0.5*FLT_MAX)
@   		return (cpackf(logf(hypotf(x / M_E, y / M_E)) + 1, atan2f(y, x)));
@ 
@ diff -c2 catrigl.c~ catrigl.c
@ *** catrigl.c~	Sun Aug 12 06:54:46 2012
@ --- catrigl.c	Mon Aug 13 12:08:21 2012
@ ***************
@ *** 119,123 ****
@   		return;
@   	}
@ ! 	if (y < MIN_4TH_ROOT) {
@   		*B_is_usable = 0;
@   		if ((int)y==0) /* raise inexact flag */
@ --- 119,123 ----
@   		return;
@   	}
@ ! 	if (!isnan(x) && y < MIN_4TH_ROOT) {
@   		*B_is_usable = 0;
@   		if ((int)y==0) /* raise inexact flag */
@ ***************
@ *** 207,214 ****
@   	if (isfinite(x) && isfinite(y) && (x > RECIP_SQRT_EPSILON_100 || y > RECIP_SQRT_EPSILON_100)) {
@   		if (huge+x+y>one) { /* raise inexact flag */
@ ! 			w = clog_for_large_values(z) + L_LN2;
@   			if (sy == 0)
@ ! 				return (cpackl(cimagl(w), -creall(w)));
@ ! 			return (cpackl(-cimagl(w), creall(w)));
@   		}
@   	}
@ --- 207,216 ----
@   	if (isfinite(x) && isfinite(y) && (x > RECIP_SQRT_EPSILON_100 || y > RECIP_SQRT_EPSILON_100)) {
@   		if (huge+x+y>one) { /* raise inexact flag */
@ ! 			w = clog_for_large_values(z);
@ ! 			rx = fabsl(cimagl(w));
@ ! 			ry = creall(w) + M_LN2;
@   			if (sy == 0)
@ ! 				ry = -ry;
@ ! 			return (cpackl(rx, ry));
@   		}
@   	}
@ ***************
@ *** 264,268 ****
@   	}
@ 
@ ! 	if (ay > 0.5*LDBL_MAX)
@   		return (cpackl(logl(hypotl(x / L_E, y / L_E)) + 1, atan2l(y, x)));
@ 
@ --- 266,270 ----
@   	}
@ 
@ ! 	if (ax > 0.5*LDBL_MAX)
@   		return (cpackl(logl(hypotl(x / L_E, y / L_E)) + 1, atan2l(y, x)));
@

Some other bugs that I noticed:

catrigf.c:

% ...
% #define MAX_4TH_ROOT		1e9	/* approx pow(FLT_MAX,0.25) */
% #define MIN_4TH_ROOT		1e-9	/* approx pow(FLT_MIN,0.25) */
% #define SQRT_EPSILON_100	1e-6	/* approx (sqrt(FLT_EPSILON)/100) */
% /* 100 is to "play it safe." */
% #define RECIP_SQRT_EPSILON_100	1e6	/* 1/SQRT_EPSILON_100 */
% #define EPSILON_100		1e-9	/* approx FLT_EPSILON/100 */
% #define RECIP_EPSILON_100	1e9	/* 1/EPSILON_100 */

These aren't float constants.  Mixing them with floats may give unwanted
extra precision and slowness.

Most of these should be hex constants, so that they are easier to
understand.  In clog() I originaly used magic hex constants, but but
almost everything was a power of 2 related to FOO_MAX or FOO_MANT_DIG,
as above, but it is difficult to translate from those to hex constants
(FLT_EPSILON / 128 could be done using token pasting as
((0x1p # FLT_MIN_EXP) * 2 / 128), but square and fourth roots are harder.
After changing the classification using bits, all the comparisions with
thresholds became comparisons of exponents, and it is now trivial to
take roots by dividing the expondent.  ld128 clogl() now works with
identical code to ld80 clogl(), based on macros in <float.h>, and the
differences for other precisions are minor (I could hide them all using
more macros).

% ...
% static const float
% one =  1.00000000000000000000e+00, 
% huge=  1.00000000000000000000e+30;

Using variables instead of macros avoids having to put F suffixes on
all float constants.

% ...
% inline static float
% f(float a, float b, float hypot_a_b)
% {
% 	if (b < 0) return (0.5 * (hypot_a_b - b));
% 	if (b == 0) return (0.5*a);
% 	return (0.5 * a*a / (hypot_a_b + b));
% }

There a squillions of 0.5's that should be 0.5F's and deserve being named
`half' more than 1 deserves being named 'one'.

catrigl.c:

% #define MAX_4TH_ROOT		1e1200L	/* approx pow(LDBL_MAX,0.25) */
% #define MIN_4TH_ROOT		1e-1200L	/* approx pow(LDBL_MIN,0.25) */
% #define SQRT_EPSILON_100	1e-13L	/* approx (sqrtl(LDBL_EPSILON)/100) */
% #define RECIP_SQRT_EPSILON_100	1e13L	/* 1/SQRT_EPSILON_100 */
% #define EPSILON_100		1e-24L	/* approx LDBL_EPSILON/100 */
% #define RECIP_EPSILON_100	1e24L	/* 1/EPSILON_100 */

Now there is no need for a suffix on the smaller constants.   You don't
use one for the 0.5's later.

The ones related to epsilon look wrong for ld128.  LDBL_EPSILON =
2**-(LDBL_MANT_DIG - 1) is way smaller when LDBL_MANT_DIG is 113 than
when it is 64.

I'm fairly happy with the attached clog() now.  All refinements that
I tried lately give either less accuracy, lower speed or larger code.
Ones that don't quite work are:
- write log(ax*ax + ay*ay) * 0.5 = log(ax) + log1p(1 + (ay/ax)**2) * 0.5.
   This avoids complications when ax is larger or ay is small (after
   ensuring than ay/ax is not small), but tends to be slower and a
   bit less accurate.
- write ax = 2**k * bx; ay = 2**k * by; log(ax*ax + ay*ay) * 0.5 =
   k * log(2) + log(bx*bx + by*by) * 0.5.  This gives marginally more
   accuracy, but tends to be slower and a bit more complicated.  One
   complication is that bx*bx + by*by may need another scaling by
   a factor of 2 or 1/2 to make it between sqrt(2)/2 and sqrt(2).

Many changes in this version:

% 	/* Avoid overflow. */
% 	if (kx >= MAX_EXP - 1)
% 		return (cpack(log(hypot(x * 0x1p-1022, y * 0x1p-1022)) +
% 		    (MAX_EXP - 2) * ln2_lo + (MAX_EXP - 2) * ln2_hi, v));
% 	if (kx >= (MAX_EXP - 1) / 2)
% 		return (cpack(log(hypot(x, y)), v));

1. Use integer exponenents kx and ky for all classifications.
2. Get all the thresholds right.
3. Scale down to near 1 here, instead of just by a factor of 2.  This
    gives some extra accuracy for no runtime cost.

% 
% 	/* Reduce inaccuracies and avoid underflow when ax is denormal. */
% 	if (kx <= MIN_EXP - 2)
% 		return (cpack(log(hypot(x * 0x1p1023, y * 0x1p1023)) +
% 		    (MIN_EXP - 2) * ln2_lo + (MIN_EXP - 2) * ln2_hi, v));

4. Scale up to near 1 here, instead of just by a factor of 2.  This
    gives considerable extra accuracy for no runtime cost.

% 
% 	/* Avoid remaining underflows (when ax is small but not denormal). */
% 	if (ky < (MIN_EXP - 1) / 2 + MANT_DIG)
% 		return (cpack(log(hypot(x, y)), v));

5. Don't scale here.  The correct scale factor is ~ 2**-kx for both cases,
    but that has more overheads.  So we only scale up when necessary to
    avoid losing considerable accuracy (for denormal ax), and let log()
    do the scaling for other cases.

% 	/* Calculate ax*ax and ay*ay exactly using Dekker's algorithm. */
% 	t = (double)(ax * (0x1p27 + 1));
% 	axh = (double)(ax - t) + t;
% 	axl = ax - axh;
% 	ax2h = ax * ax;
% 	ax2l = axh * axh - ax2h + 2 * axh * axl + axl * axl;
% 	t = (double)(ay * (0x1p27 + 1));
% 	ayh = (double)(ay - t) + t;
% 	ayl = ay - ayh;
% 	ay2h = ay * ay;
% 	ay2l = ayh * ayh - ay2h + 2 * ayh * ayl + ayl * ayl;

6. Additive splitting like I had for clogl() before doesn't work unless
    ax is near 1.  Use the correct Veldkamp algorithm after googling
    Dekker's algorithms.  ax has type double_t, so casting to double
    avoids compiler bugfeatures at some cost.

% 	sh -= 1;
% 	norm(sh, sl);
% 	norm(ax2l, ay2l);
% 	/* Briggs-Kahan algorithm (except we discard the final low term): */
% 	norm(sh, ax2l);
% 	norm(sl, ay2l);
% 	t = ax2l + sl;
% 	normF(sh, t);
% 	return (cpack(log1p(ay2l + t + sh) * 0.5, v));

7. Use  a full modernised Dekker's algorithm for the critical case of
    |z| very near 1 (and for many cases not so near 1).  There are 2
    Veldkamp splittings, 4 norm() (= 2sum) calls and 2 normF() (= 2sumF)
    calls on the way here.  norm() takes 6 additions and normF() takes 3,
    so there are 30 additions just for the norm*()'s.  But this is only
    moderately slow (about the same speed as extra branches to avoid
    doing it all so much).

Bruce
--0-1116022701-1344877047=:3692
Content-Type: TEXT/PLAIN; charset=US-ASCII; name="cplex.c"
Content-Transfer-Encoding: BASE64
Content-ID: <20120814025727.Q3692@besplex.bde.org>
Content-Description: 
Content-Disposition: attachment; filename="cplex.c"

I2luY2x1ZGUgPGNvbXBsZXguaD4NCiNpbmNsdWRlIDxmbG9hdC5oPg0KDQoj
aW5jbHVkZSAiZnBtYXRoLmgiDQojaW5jbHVkZSAibG9jYWwuaCINCiNpbmNs
dWRlICJtYXRoLmgiDQojaW5jbHVkZSAibWF0aF9wcml2YXRlLmgiDQoNCi8q
IDJzdW0gYWxnb3JpdGhtLiAqLw0KI3VuZGVmIG5vcm0NCiNkZWZpbmUJbm9y
bShhLCBiKSBkbyB7CQlcDQoJX190eXBlb2YoYSkgX19zLCBfX3c7CVwNCgkJ
CQlcDQoJX193ID0gKGEpICsgKGIpOwlcDQoJX19zID0gX193IC0gKGEpOwlc
DQoJKGIpID0gKChhKSAtIChfX3cgLSBfX3MpKSArICgoYikgLSBfX3MpOyBc
DQoJKGEpID0gX193OwkJXA0KfSB3aGlsZSAoMCkNCg0KLyogMnN1bUYgYWxn
b3JpdGhtLiAqLw0KI2RlZmluZQlub3JtRihhLCBiKSBkbyB7CVwNCglfX3R5
cGVvZihhKSBfX3c7CVwNCgkJCQlcDQoJX193ID0gKGEpICsgKGIpOwlcDQoJ
KGIpID0gKChhKSAtIF9fdykgKyAoYik7IFwNCgkoYSkgPSBfX3c7CQlcDQp9
IHdoaWxlICgwKQ0KDQojZGVmaW5lCU1BTlRfRElHCURCTF9NQU5UX0RJRw0K
I2RlZmluZQlNQVhfRVhQCQlEQkxfTUFYX0VYUA0KI2RlZmluZQlNSU5fRVhQ
CQlEQkxfTUlOX0VYUA0KDQpzdGF0aWMgY29uc3QgZG91YmxlDQpsbjJfaGkg
PSA2LjkzMTQ3MTgwNTU4Mjk4NzFlLTEsCQkvKiAgMHgxNjJlNDJmZWZhMDAw
MC4wcC01MyAqLw0KbG4yX2xvID0gMS42NDY1OTQ5NTgyODk3MDgyZS0xMjsJ
LyogIDB4MWNmNzlhYmM5ZTNiM2EuMHAtOTIgKi8NCg0KZG91YmxlIGNvbXBs
ZXgNCmNsb2coZG91YmxlIGNvbXBsZXggeikNCnsNCglkb3VibGVfdCBheCwg
YXgyaCwgYXgybCwgYXhoLCBheGwsIGF5LCBheTJoLCBheTJsLCBheWgsIGF5
bCwgc2gsIHNsLCB0Ow0KCWRvdWJsZSB4LCB5LCB2Ow0KCXVpbnQzMl90IGhh
eCwgaGF5Ow0KCWludCBreCwga3k7DQoNCgl4ID0gY3JlYWwoeik7DQoJeSA9
IGNpbWFnKHopOw0KCXYgPSBhdGFuMih5LCB4KTsNCg0KCWF4ID0gZmFicyh4
KTsNCglheSA9IGZhYnMoeSk7DQoJaWYgKGF4IDwgYXkpIHsNCgkJdCA9IGF4
Ow0KCQlheCA9IGF5Ow0KCQlheSA9IHQ7DQoJfQ0KDQoJR0VUX0hJR0hfV09S
RChoYXgsIGF4KTsNCglreCA9IChoYXggPj4gMjApIC0gMTAyMzsNCglHRVRf
SElHSF9XT1JEKGhheSwgYXkpOw0KCWt5ID0gKGhheSA+PiAyMCkgLSAxMDIz
Ow0KDQoJLyogSGFuZGxlIE5hTnMgYW5kIEluZnMgdXNpbmcgdGhlIGdlbmVy
YWwgZm9ybXVsYS4gKi8NCglpZiAoa3ggPT0gTUFYX0VYUCB8fCBreSA9PSBN
QVhfRVhQKQ0KCQlyZXR1cm4gKGNwYWNrKGxvZyhoeXBvdCh4LCB5KSksIHYp
KTsNCg0KCS8qIEF2b2lkIHNwdXJpb3VzIHVuZGVyZmxvdywgYW5kIHJlZHVj
ZSBpbmFjY3VyYWNpZXMgd2hlbiBheCBpcyAxLiAqLw0KCWlmIChheCA9PSAx
KSB7DQoJCWlmIChreSA8IChNSU5fRVhQIC0gMSkgLyAyKQ0KCQkJcmV0dXJu
IChjcGFjaygoYXkgKiAwLjUpICogYXksIHYpKTsNCgkJcmV0dXJuIChjcGFj
ayhsb2cxcChheSAqIGF5KSAqIDAuNSwgdikpOw0KCX0NCg0KCS8qIEF2b2lk
IHVuZGVyZmxvdyB3aGVuIGF4IGlzIG5vdCBzbWFsbC4gIEFsc28gaGFuZGxl
IHplcm8gYXJncy4gKi8NCglpZiAoa3ggLSBreSA+IE1BTlRfRElHIHx8IGF5
ID09IDApDQoJCXJldHVybiAoY3BhY2sobG9nKGF4KSwgdikpOw0KDQoJLyog
QXZvaWQgb3ZlcmZsb3cuICovDQoJaWYgKGt4ID49IE1BWF9FWFAgLSAxKQ0K
CQlyZXR1cm4gKGNwYWNrKGxvZyhoeXBvdCh4ICogMHgxcC0xMDIyLCB5ICog
MHgxcC0xMDIyKSkgKw0KCQkgICAgKE1BWF9FWFAgLSAyKSAqIGxuMl9sbyAr
IChNQVhfRVhQIC0gMikgKiBsbjJfaGksIHYpKTsNCglpZiAoa3ggPj0gKE1B
WF9FWFAgLSAxKSAvIDIpDQoJCXJldHVybiAoY3BhY2sobG9nKGh5cG90KHgs
IHkpKSwgdikpOw0KDQoJLyogUmVkdWNlIGluYWNjdXJhY2llcyBhbmQgYXZv
aWQgdW5kZXJmbG93IHdoZW4gYXggaXMgZGVub3JtYWwuICovDQoJaWYgKGt4
IDw9IE1JTl9FWFAgLSAyKQ0KCQlyZXR1cm4gKGNwYWNrKGxvZyhoeXBvdCh4
ICogMHgxcDEwMjMsIHkgKiAweDFwMTAyMykpICsNCgkJICAgIChNSU5fRVhQ
IC0gMikgKiBsbjJfbG8gKyAoTUlOX0VYUCAtIDIpICogbG4yX2hpLCB2KSk7
DQoNCgkvKiBBdm9pZCByZW1haW5pbmcgdW5kZXJmbG93cyAod2hlbiBheCBp
cyBzbWFsbCBidXQgbm90IGRlbm9ybWFsKS4gKi8NCglpZiAoa3kgPCAoTUlO
X0VYUCAtIDEpIC8gMiArIE1BTlRfRElHKQ0KCQlyZXR1cm4gKGNwYWNrKGxv
ZyhoeXBvdCh4LCB5KSksIHYpKTsNCg0KCS8qIENhbGN1bGF0ZSBheCpheCBh
bmQgYXkqYXkgZXhhY3RseSB1c2luZyBEZWtrZXIncyBhbGdvcml0aG0uICov
DQoJdCA9IChkb3VibGUpKGF4ICogKDB4MXAyNyArIDEpKTsNCglheGggPSAo
ZG91YmxlKShheCAtIHQpICsgdDsNCglheGwgPSBheCAtIGF4aDsNCglheDJo
ID0gYXggKiBheDsNCglheDJsID0gYXhoICogYXhoIC0gYXgyaCArIDIgKiBh
eGggKiBheGwgKyBheGwgKiBheGw7DQoJdCA9IChkb3VibGUpKGF5ICogKDB4
MXAyNyArIDEpKTsNCglheWggPSAoZG91YmxlKShheSAtIHQpICsgdDsNCglh
eWwgPSBheSAtIGF5aDsNCglheTJoID0gYXkgKiBheTsNCglheTJsID0gYXlo
ICogYXloIC0gYXkyaCArIDIgKiBheWggKiBheWwgKyBheWwgKiBheWw7DQoN
CgkvKg0KCSAqIFdoZW4gbG9nKHx6fCkgaXMgZmFyIGZyb20gMSwgYWNjdXJh
Y3kgaW4gY2FsY3VsYXRpbmcgdGhlIHN1bQ0KCSAqIG9mIHRoZSBzcXVhcmVz
IGlzIG5vdCB2ZXJ5IGltcG9ydGFudCBzaW5jZSBsb2coKSByZWR1Y2VzDQoJ
ICogaW5hY2N1cmFjaWVzLiAgV2UgZGVwZW5kZWQgb24gdGhpcyB0byB1c2Ug
dGhlIGdlbmVyYWwNCgkgKiBmb3JtdWxhIHdoZW4gbG9nKHx6fCkgaXMgdmVy
eSBmYXIgZnJvbSAxLiAgV2hlbiBsb2cofHp8KSBpcw0KCSAqIG1vZGVyYXRl
bHkgZmFyIGZyb20gMSwgd2UgZ28gdGhyb3VnaCB0aGUgZXh0cmEtcHJlY2lz
aW9uDQoJICogY2FsY3VsYXRpb25zIHRvIHJlZHVjZSBicmFuY2hlcyBhbmQg
Z2FpbiBhIGxpdHRsZSBhY2N1cmFjeS4NCgkgKg0KCSAqIFdoZW4gfHp8IGlz
IG5lYXIgMSwgd2Ugc3VidHJhY3QgMSBhbmQgdXNlIGxvZzFwKCkgYW5kIGRv
bid0DQoJICogbGVhdmUgaXQgdG8gbG9nKCkgdG8gc3VidHJhY3QgMSwgc2lu
Y2Ugd2UgZ2FpbiBhdCBsZWFzdCAxIGJpdA0KCSAqIG9mIGFjY3VyYWN5IGlu
IHRoaXMgd2F5Lg0KCSAqDQoJICogV2hlbiB8enwgaXMgdmVyeSBuZWFyIDEs
IHN1YnRyYWN0aW5nIDEgY2FuIGNhbmNlbCBhbG1vc3QNCgkgKiAzKk1BTlRf
RElHIGJpdHMuICBXZSBhcnJhbmdlIHRoYXQgc3VidHJhY3RpbmcgMSBpcyBl
eGFjdCBpbg0KCSAqIGRvdWJsZWQgcHJlY2lzaW9uLCBhbmQgdGhlbiBkbyB0
aGUgcmVzdCBvZiB0aGUgY2FsY3VsYXRpb24NCgkgKiBpbiBzbG9wcHkgZG91
YmxlZCBwcmVjaXNpb24uICBBbHRob3VnaCBsYXJnZSBjYW5jZWxhdGlvbnMN
CgkgKiBvZnRlbiBsb3NlIGxvdHMgb2YgYWNjdXJhY3ksIGhlcmUgdGhlIGZp
bmFsIHJlc3VsdCBpcyBleGFjdA0KCSAqIGluIGRvdWJsZWQgcHJlY2lzaW9u
IGlmIHRoZSBsYXJnZSBjYWxjdWxhdGlvbiBvY2N1cnMgKGJlY2F1c2UNCgkg
KiB0aGVuIGl0IGlzIGV4YWN0IGluIHRyaXBsZWQgcHJlY2lzaW9uIGFuZCB0
aGUgY2FuY2VsYXRpb24NCgkgKiByZW1vdmVzIGVub3VnaCBiaXRzIHRvIGZp
dCBpbiBkb3VibGVkIHByZWNpc2lvbikuICBUaHVzIHRoZQ0KCSAqIHJlc3Vs
dCBpcyBhY2N1cmF0ZSBpbiBzbG9wcHkgZG91YmxlZCBwcmVjaXNpb24sIGFu
ZCB0aGUgb25seQ0KCSAqIHNpZ25pZmljYW50IGxvc3Mgb2YgYWNjdXJhY3kg
aXMgd2hlbiBpdCBpcyBzdW1tZWQgYW5kIHBhc3NlZA0KCSAqIHRvIGxvZzFw
KCkuDQoJICovDQoJc2ggPSBheDJoOw0KCXNsID0gYXkyaDsNCglub3JtRihz
aCwgc2wpOw0KCWlmIChzaCA8IDAuNSB8fCBzaCA+PSAzKQ0KCQlyZXR1cm4g
KGNwYWNrKGxvZyhheTJsICsgYXgybCArIHNsICsgc2gpICogMC41LCB2KSk7
DQoJc2ggLT0gMTsNCglub3JtKHNoLCBzbCk7DQoJbm9ybShheDJsLCBheTJs
KTsNCgkvKiBCcmlnZ3MtS2FoYW4gYWxnb3JpdGhtIChleGNlcHQgd2UgZGlz
Y2FyZCB0aGUgZmluYWwgbG93IHRlcm0pOiAqLw0KCW5vcm0oc2gsIGF4Mmwp
Ow0KCW5vcm0oc2wsIGF5MmwpOw0KCXQgPSBheDJsICsgc2w7DQoJbm9ybUYo
c2gsIHQpOw0KCXJldHVybiAoY3BhY2sobG9nMXAoYXkybCArIHQgKyBzaCkg
KiAwLjUsIHYpKTsNCn0NCg0KI2lmIChMREJMX01BTlRfRElHID09IDUzKQ0K
X193ZWFrX3JlZmVyZW5jZShjbG9nLCBjbG9nbCk7DQojZW5kaWYNCg0KI3Vu
ZGVmIE1BTlRfRElHDQojZGVmaW5lCU1BTlRfRElHCUZMVF9NQU5UX0RJRw0K
I3VuZGVmIE1BWF9FWFANCiNkZWZpbmUJTUFYX0VYUAkJRkxUX01BWF9FWFAN
CiN1bmRlZiBNSU5fRVhQDQojZGVmaW5lCU1JTl9FWFAJCUZMVF9NSU5fRVhQ
DQoNCnN0YXRpYyBjb25zdCBmbG9hdA0KbG4yZl9oaSA9ICA2LjkzMTQ1NzUx
OTVlLTEsCQkvKiAgMHhiMTcyMDAuMHAtMjQgKi8NCmxuMmZfbG8gPSAgMS40
Mjg2MDY3NjUzZS02OwkJLyogIDB4YmZiZThlLjBwLTQzICovDQoNCmZsb2F0
IGNvbXBsZXgNCmNsb2dmKGZsb2F0IGNvbXBsZXggeikNCnsNCglmbG9hdF90
IGF4LCBheDJoLCBheDJsLCBheGgsIGF4bCwgYXksIGF5MmgsIGF5MmwsIGF5
aCwgYXlsLCBzaCwgc2wsIHQ7DQoJZmxvYXQgeCwgeSwgdjsNCgl1aW50MzJf
dCBoYXgsIGhheTsNCglpbnQga3gsIGt5Ow0KDQoJeCA9IGNyZWFsZih6KTsN
Cgl5ID0gY2ltYWdmKHopOw0KCXYgPSBhdGFuMmYoeSwgeCk7DQoNCglheCA9
IGZhYnNmKHgpOw0KCWF5ID0gZmFic2YoeSk7DQoJaWYgKGF4IDwgYXkpIHsN
CgkJdCA9IGF4Ow0KCQlheCA9IGF5Ow0KCQlheSA9IHQ7DQoJfQ0KDQoJR0VU
X0ZMT0FUX1dPUkQoaGF4LCBheCk7DQoJa3ggPSAoaGF4ID4+IDIzKSAtIDEy
NzsNCglHRVRfRkxPQVRfV09SRChoYXksIGF5KTsNCglreSA9IChoYXkgPj4g
MjMpIC0gMTI3Ow0KDQoJLyogSGFuZGxlIE5hTnMgYW5kIEluZnMgdXNpbmcg
dGhlIGdlbmVyYWwgZm9ybXVsYS4gKi8NCglpZiAoa3ggPT0gTUFYX0VYUCB8
fCBreSA9PSBNQVhfRVhQKQ0KCQlyZXR1cm4gKGNwYWNrZihsb2dmKGh5cG90
Zih4LCB5KSksIHYpKTsNCg0KCS8qIEF2b2lkIHNwdXJpb3VzIHVuZGVyZmxv
dywgYW5kIHJlZHVjZSBpbmFjY3VyYWNpZXMgd2hlbiBheCBpcyAxLiAqLw0K
CWlmIChoYXggPT0gMHgzZjgwMDAwMCkgew0KCQlpZiAoa3kgPCAoTUlOX0VY
UCAtIDEpIC8gMikNCgkJCXJldHVybiAoY3BhY2tmKChheSAqIDAuNUYpICog
YXksIHYpKTsNCgkJcmV0dXJuIChjcGFja2YobG9nMXBmKGF5ICogYXkpICog
MC41RiwgdikpOw0KCX0NCg0KCS8qIEF2b2lkIHVuZGVyZmxvdyB3aGVuIGF4
IGlzIG5vdCBzbWFsbC4gIEFsc28gaGFuZGxlIHplcm8gYXJncy4gKi8NCglp
ZiAoa3ggLSBreSA+IE1BTlRfRElHIHx8IGhheSA9PSAwKQ0KCQlyZXR1cm4g
KGNwYWNrZihsb2dmKGF4KSwgdikpOw0KDQoJLyogQXZvaWQgb3ZlcmZsb3cu
ICovDQoJaWYgKGt4ID49IE1BWF9FWFAgLSAxKQ0KCQlyZXR1cm4gKGNwYWNr
Zihsb2dmKGh5cG90Zih4ICogMHgxcC0xMjZGLCB5ICogMHgxcC0xMjZGKSkg
Kw0KCQkgICAgKE1BWF9FWFAgLSAyKSAqIGxuMl9sbyArIChNQVhfRVhQIC0g
MikgKiBsbjJfaGksIHYpKTsNCglpZiAoa3ggPj0gKE1BWF9FWFAgLSAxKSAv
IDIpDQoJCXJldHVybiAoY3BhY2tmKGxvZ2YoaHlwb3RmKHgsIHkpKSwgdikp
Ow0KDQoJLyogUmVkdWNlIGluYWNjdXJhY2llcyBhbmQgYXZvaWQgdW5kZXJm
bG93IHdoZW4gYXggaXMgZGVub3JtYWwuICovDQoJaWYgKGt4IDw9IE1JTl9F
WFAgLSAyKQ0KCQlyZXR1cm4gKGNwYWNrZihsb2dmKGh5cG90Zih4ICogMHgx
cDEyN0YsIHkgKiAweDFwMTI3RikpICsNCgkJICAgIChNSU5fRVhQIC0gMikg
KiBsbjJmX2xvICsgKE1JTl9FWFAgLSAyKSAqIGxuMmZfaGksIHYpKTsNCg0K
CS8qIEF2b2lkIHJlbWFpbmluZyB1bmRlcmZsb3dzICh3aGVuIGF4IGlzIHNt
YWxsIGJ1dCBub3QgZGVub3JtYWwpLiAqLw0KCWlmIChreSA8IChNSU5fRVhQ
IC0gMSkgLyAyICsgTUFOVF9ESUcpDQoJCXJldHVybiAoY3BhY2tmKGxvZ2Yo
aHlwb3RmKHgsIHkpKSwgdikpOw0KDQoJLyogQ2FsY3VsYXRlIGF4KmF4IGFu
ZCBheSpheSBleGFjdGx5IHVzaW5nIERla2tlcidzIGFsZ29yaXRobS4gKi8N
Cgl0ID0gKGZsb2F0KShheCAqICgweDFwMTJGICsgMSkpOw0KCWF4aCA9IChm
bG9hdCkoYXggLSB0KSArIHQ7DQoJYXhsID0gYXggLSBheGg7DQoJYXgyaCA9
IGF4ICogYXg7DQoJYXgybCA9IGF4aCAqIGF4aCAtIGF4MmggKyAyICogYXho
ICogYXhsICsgYXhsICogYXhsOw0KCXQgPSAoZmxvYXQpKGF5ICogKDB4MXAx
MkYgKyAxKSk7DQoJYXloID0gKGZsb2F0KShheSAtIHQpICsgdDsNCglheWwg
PSBheSAtIGF5aDsNCglheTJoID0gYXkgKiBheTsNCglheTJsID0gYXloICog
YXloIC0gYXkyaCArIDIgKiBheWggKiBheWwgKyBheWwgKiBheWw7DQoNCgkv
Kg0KCSAqIFdoZW4gbG9nKHx6fCkgaXMgZmFyIGZyb20gMSwgYWNjdXJhY3kg
aW4gY2FsY3VsYXRpbmcgdGhlIHN1bQ0KCSAqIG9mIHRoZSBzcXVhcmVzIGlz
IG5vdCB2ZXJ5IGltcG9ydGFudCBzaW5jZSBsb2coKSByZWR1Y2VzDQoJICog
aW5hY2N1cmFjaWVzLiAgV2UgZGVwZW5kZWQgb24gdGhpcyB0byB1c2UgdGhl
IGdlbmVyYWwNCgkgKiBmb3JtdWxhIHdoZW4gbG9nKHx6fCkgaXMgdmVyeSBm
YXIgZnJvbSAxLiAgV2hlbiBsb2cofHp8KSBpcw0KCSAqIG1vZGVyYXRlbHkg
ZmFyIGZyb20gMSwgd2UgZ28gdGhyb3VnaCB0aGUgZXh0cmEtcHJlY2lzaW9u
DQoJICogY2FsY3VsYXRpb25zIHRvIHJlZHVjZSBicmFuY2hlcyBhbmQgZ2Fp
biBhIGxpdHRsZSBhY2N1cmFjeS4NCgkgKg0KCSAqIFdoZW4gfHp8IGlzIG5l
YXIgMSwgd2Ugc3VidHJhY3QgMSBhbmQgdXNlIGxvZzFwKCkgYW5kIGRvbid0
DQoJICogbGVhdmUgaXQgdG8gbG9nKCkgdG8gc3VidHJhY3QgMSwgc2luY2Ug
d2UgZ2FpbiBhdCBsZWFzdCAxIGJpdA0KCSAqIG9mIGFjY3VyYWN5IGluIHRo
aXMgd2F5Lg0KCSAqDQoJICogV2hlbiB8enwgaXMgdmVyeSBuZWFyIDEsIHN1
YnRyYWN0aW5nIDEgY2FuIGNhbmNlbCBhbG1vc3QNCgkgKiAzKk1BTlRfRElH
IGJpdHMuICBXZSBhcnJhbmdlIHRoYXQgc3VidHJhY3RpbmcgMSBpcyBleGFj
dCBpbg0KCSAqIGRvdWJsZWQgcHJlY2lzaW9uLCBhbmQgdGhlbiBkbyB0aGUg
cmVzdCBvZiB0aGUgY2FsY3VsYXRpb24NCgkgKiBpbiBzbG9wcHkgZG91Ymxl
ZCBwcmVjaXNpb24uICBBbHRob3VnaCBsYXJnZSBjYW5jZWxhdGlvbnMNCgkg
KiBvZnRlbiBsb3NlIGxvdHMgb2YgYWNjdXJhY3ksIGhlcmUgdGhlIGZpbmFs
IHJlc3VsdCBpcyBleGFjdA0KCSAqIGluIGRvdWJsZWQgcHJlY2lzaW9uIGlm
IHRoZSBsYXJnZSBjYWxjdWxhdGlvbiBvY2N1cnMgKGJlY2F1c2UNCgkgKiB0
aGVuIGl0IGlzIGV4YWN0IGluIHRyaXBsZWQgcHJlY2lzaW9uIGFuZCB0aGUg
Y2FuY2VsYXRpb24NCgkgKiByZW1vdmVzIGVub3VnaCBiaXRzIHRvIGZpdCBp
biBkb3VibGVkIHByZWNpc2lvbikuICBUaHVzIHRoZQ0KCSAqIHJlc3VsdCBp
cyBhY2N1cmF0ZSBpbiBzbG9wcHkgZG91YmxlZCBwcmVjaXNpb24sIGFuZCB0
aGUgb25seQ0KCSAqIHNpZ25pZmljYW50IGxvc3Mgb2YgYWNjdXJhY3kgaXMg
d2hlbiBpdCBpcyBzdW1tZWQgYW5kIHBhc3NlZA0KCSAqIHRvIGxvZzFwKCku
DQoJICovDQoJc2ggPSBheDJoOw0KCXNsID0gYXkyaDsNCglub3JtRihzaCwg
c2wpOw0KCWlmIChzaCA8IDAuNUYgfHwgc2ggPj0gMykNCgkJcmV0dXJuIChj
cGFja2YobG9nZihheTJsICsgYXgybCArIHNsICsgc2gpICogMC41Riwgdikp
Ow0KCXNoIC09IDE7DQoJbm9ybShzaCwgc2wpOw0KCW5vcm0oYXgybCwgYXky
bCk7DQoJLyogQnJpZ2dzLUthaGFuIGFsZ29yaXRobSAoZXhjZXB0IHdlIGRp
c2NhcmQgdGhlIGZpbmFsIGxvdyB0ZXJtKTogKi8NCglub3JtKHNoLCBheDJs
KTsNCglub3JtKHNsLCBheTJsKTsNCgl0ID0gYXgybCArIHNsOw0KCW5vcm1G
KHNoLCB0KTsNCglyZXR1cm4gKGNwYWNrZihsb2cxcGYoYXkybCArIHQgKyBz
aCkgKiAwLjVGLCB2KSk7DQp9DQoNCiN1bmRlZiBNQU5UX0RJRw0KI2RlZmlu
ZQlNQU5UX0RJRwlMREJMX01BTlRfRElHDQojdW5kZWYgTUFYX0VYUA0KI2Rl
ZmluZQlNQVhfRVhQCQlMREJMX01BWF9FWFANCiN1bmRlZiBNSU5fRVhQDQoj
ZGVmaW5lCU1JTl9FWFAJCUxEQkxfTUlOX0VYUA0KDQpsb25nIGRvdWJsZSBj
b21wbGV4DQpjbG9nbChsb25nIGRvdWJsZSBjb21wbGV4IHopDQp7DQoJbG9u
ZyBkb3VibGUgYXgsIGF4MmgsIGF4MmwsIGF4aCwgYXhsLCBheSwgYXkyaCwg
YXkybCwgYXloLCBheWw7DQoJbG9uZyBkb3VibGUgc2gsIHNsLCB0Ow0KCWxv
bmcgZG91YmxlIHgsIHksIHY7DQoJdWludDE2X3QgaGF4LCBoYXk7DQoJaW50
IGt4LCBreTsNCg0KCXggPSBjcmVhbGwoeik7DQoJeSA9IGNpbWFnbCh6KTsN
Cgl2ID0gYXRhbjJsKHksIHgpOw0KDQoJYXggPSBmYWJzbCh4KTsNCglheSA9
IGZhYnNsKHkpOw0KCWlmIChheCA8IGF5KSB7DQoJCXQgPSBheDsNCgkJYXgg
PSBheTsNCgkJYXkgPSB0Ow0KCX0NCg0KCUdFVF9MREJMX0VYUFNJR04oaGF4
LCBheCk7DQoJa3ggPSBoYXggLSAxNjM4MzsNCglHRVRfTERCTF9FWFBTSUdO
KGhheSwgYXkpOw0KCWt5ID0gaGF5IC0gMTYzODM7DQoNCgkvKiBIYW5kbGUg
TmFOcyBhbmQgSW5mcyB1c2luZyB0aGUgZ2VuZXJhbCBmb3JtdWxhLiAqLw0K
CWlmIChreCA9PSBNQVhfRVhQIHx8IGt5ID09IE1BWF9FWFApDQoJCXJldHVy
biAoY3BhY2tsKGxvZ2woaHlwb3RsKHgsIHkpKSwgdikpOw0KDQoJLyogQXZv
aWQgc3B1cmlvdXMgdW5kZXJmbG93LCBhbmQgcmVkdWNlIGluYWNjdXJhY2ll
cyB3aGVuIGF4IGlzIDEuICovDQoJaWYgKGF4ID09IDEpIHsNCgkJaWYgKGt5
IDwgKE1JTl9FWFAgLSAxKSAvIDIpDQoJCQlyZXR1cm4gKGNwYWNrbCgoYXkg
KiAwLjUpICogYXksIHYpKTsNCgkJcmV0dXJuIChjcGFja2wobG9nMXBsKGF5
ICogYXkpICogMC41LCB2KSk7DQoJfQ0KDQoJLyogQXZvaWQgdW5kZXJmbG93
IHdoZW4gYXggaXMgbm90IHNtYWxsLiAgQWxzbyBoYW5kbGUgemVybyBhcmdz
LiAqLw0KCWlmIChreCAtIGt5ID4gTUFOVF9ESUcgfHwgYXkgPT0gMCkNCgkJ
cmV0dXJuIChjcGFja2wobG9nbChheCksIHYpKTsNCg0KCS8qIEF2b2lkIG92
ZXJmbG93LiAqLw0KCWlmIChreCA+PSBNQVhfRVhQIC0gMSkNCgkJcmV0dXJu
IChjcGFja2wobG9nbChoeXBvdGwoeCAqIDB4MXAtMTYzODJMLCB5ICogMHgx
cC0xNjM4MkwpKSArDQoJCSAgICAoTUFYX0VYUCAtIDIpICogbG4yX2xvICsg
KE1BWF9FWFAgLSAyKSAqIGxuMl9oaSwgdikpOw0KCWlmIChreCA+PSAoTUFY
X0VYUCAtIDEpIC8gMikNCgkJcmV0dXJuIChjcGFja2wobG9nbChoeXBvdGwo
eCwgeSkpLCB2KSk7DQoNCgkvKiBSZWR1Y2UgaW5hY2N1cmFjaWVzIGFuZCBh
dm9pZCB1bmRlcmZsb3cgd2hlbiBheCBpcyBkZW5vcm1hbC4gKi8NCglpZiAo
a3ggPD0gTUlOX0VYUCAtIDIpDQoJCXJldHVybiAoY3BhY2tsKGxvZ2woaHlw
b3RsKHggKiAweDFwMTYzODNMLCB5ICogMHgxcDE2MzgzTCkpICsNCgkJICAg
IChNSU5fRVhQIC0gMikgKiBsbjJfbG8gKyAoTUlOX0VYUCAtIDIpICogbG4y
X2hpLCB2KSk7DQoNCgkvKiBBdm9pZCByZW1haW5pbmcgdW5kZXJmbG93cyAo
d2hlbiBheCBpcyBzbWFsbCBidXQgbm90IGRlbm9ybWFsKS4gKi8NCglpZiAo
a3kgPCAoTUlOX0VYUCAtIDEpIC8gMiArIE1BTlRfRElHKQ0KCQlyZXR1cm4g
KGNwYWNrbChsb2dsKGh5cG90bCh4LCB5KSksIHYpKTsNCg0KCS8qIENhbGN1
bGF0ZSBheCpheCBhbmQgYXkqYXkgZXhhY3RseSB1c2luZyBEZWtrZXIncyBh
bGdvcml0aG0uICovDQoJdCA9IChsb25nIGRvdWJsZSkoYXggKiAoMHgxcDMy
ICsgMSkpOw0KCWF4aCA9IChsb25nIGRvdWJsZSkoYXggLSB0KSArIHQ7DQoJ
YXhsID0gYXggLSBheGg7DQoJYXgyaCA9IGF4ICogYXg7DQoJYXgybCA9IGF4
aCAqIGF4aCAtIGF4MmggKyAyICogYXhoICogYXhsICsgYXhsICogYXhsOw0K
CXQgPSAobG9uZyBkb3VibGUpKGF5ICogKDB4MXAzMiArIDEpKTsNCglheWgg
PSAobG9uZyBkb3VibGUpKGF5IC0gdCkgKyB0Ow0KCWF5bCA9IGF5IC0gYXlo
Ow0KCWF5MmggPSBheSAqIGF5Ow0KCWF5MmwgPSBheWggKiBheWggLSBheTJo
ICsgMiAqIGF5aCAqIGF5bCArIGF5bCAqIGF5bDsNCg0KCS8qDQoJICogV2hl
biBsb2cofHp8KSBpcyBmYXIgZnJvbSAxLCBhY2N1cmFjeSBpbiBjYWxjdWxh
dGluZyB0aGUgc3VtDQoJICogb2YgdGhlIHNxdWFyZXMgaXMgbm90IHZlcnkg
aW1wb3J0YW50IHNpbmNlIGxvZygpIHJlZHVjZXMNCgkgKiBpbmFjY3VyYWNp
ZXMuICBXZSBkZXBlbmRlZCBvbiB0aGlzIHRvIHVzZSB0aGUgZ2VuZXJhbA0K
CSAqIGZvcm11bGEgd2hlbiBsb2cofHp8KSBpcyB2ZXJ5IGZhciBmcm9tIDEu
ICBXaGVuIGxvZyh8enwpIGlzDQoJICogbW9kZXJhdGVseSBmYXIgZnJvbSAx
LCB3ZSBnbyB0aHJvdWdoIHRoZSBleHRyYS1wcmVjaXNpb24NCgkgKiBjYWxj
dWxhdGlvbnMgdG8gcmVkdWNlIGJyYW5jaGVzIGFuZCBnYWluIGEgbGl0dGxl
IGFjY3VyYWN5Lg0KCSAqDQoJICogV2hlbiB8enwgaXMgbmVhciAxLCB3ZSBz
dWJ0cmFjdCAxIGFuZCB1c2UgbG9nMXAoKSBhbmQgZG9uJ3QNCgkgKiBsZWF2
ZSBpdCB0byBsb2coKSB0byBzdWJ0cmFjdCAxLCBzaW5jZSB3ZSBnYWluIGF0
IGxlYXN0IDEgYml0DQoJICogb2YgYWNjdXJhY3kgaW4gdGhpcyB3YXkuDQoJ
ICoNCgkgKiBXaGVuIHx6fCBpcyB2ZXJ5IG5lYXIgMSwgc3VidHJhY3Rpbmcg
MSBjYW4gY2FuY2VsIGFsbW9zdA0KCSAqIDMqTUFOVF9ESUcgYml0cy4gIFdl
IGFycmFuZ2UgdGhhdCBzdWJ0cmFjdGluZyAxIGlzIGV4YWN0IGluDQoJICog
ZG91YmxlZCBwcmVjaXNpb24sIGFuZCB0aGVuIGRvIHRoZSByZXN0IG9mIHRo
ZSBjYWxjdWxhdGlvbg0KCSAqIGluIHNsb3BweSBkb3VibGVkIHByZWNpc2lv
bi4gIEFsdGhvdWdoIGxhcmdlIGNhbmNlbGF0aW9ucw0KCSAqIG9mdGVuIGxv
c2UgbG90cyBvZiBhY2N1cmFjeSwgaGVyZSB0aGUgZmluYWwgcmVzdWx0IGlz
IGV4YWN0DQoJICogaW4gZG91YmxlZCBwcmVjaXNpb24gaWYgdGhlIGxhcmdl
IGNhbGN1bGF0aW9uIG9jY3VycyAoYmVjYXVzZQ0KCSAqIHRoZW4gaXQgaXMg
ZXhhY3QgaW4gdHJpcGxlZCBwcmVjaXNpb24gYW5kIHRoZSBjYW5jZWxhdGlv
bg0KCSAqIHJlbW92ZXMgZW5vdWdoIGJpdHMgdG8gZml0IGluIGRvdWJsZWQg
cHJlY2lzaW9uKS4gIFRodXMgdGhlDQoJICogcmVzdWx0IGlzIGFjY3VyYXRl
IGluIHNsb3BweSBkb3VibGVkIHByZWNpc2lvbiwgYW5kIHRoZSBvbmx5DQoJ
ICogc2lnbmlmaWNhbnQgbG9zcyBvZiBhY2N1cmFjeSBpcyB3aGVuIGl0IGlz
IHN1bW1lZCBhbmQgcGFzc2VkDQoJICogdG8gbG9nMXAoKS4NCgkgKi8NCglz
aCA9IGF4Mmg7DQoJc2wgPSBheTJoOw0KCW5vcm1GKHNoLCBzbCk7DQoJaWYg
KHNoIDwgMC41IHx8IHNoID49IDMpDQoJCXJldHVybiAoY3BhY2tsKGxvZ2wo
YXkybCArIGF4MmwgKyBzbCArIHNoKSAqIDAuNSwgdikpOw0KCXNoIC09IDE7
DQoJbm9ybShzaCwgc2wpOw0KCW5vcm0oYXgybCwgYXkybCk7DQoJLyogQnJp
Z2dzLUthaGFuIGFsZ29yaXRobSAoZXhjZXB0IHdlIGRpc2NhcmQgdGhlIGZp
bmFsIGxvdyB0ZXJtKTogKi8NCglub3JtKHNoLCBheDJsKTsNCglub3JtKHNs
LCBheTJsKTsNCgl0ID0gYXgybCArIHNsOw0KCW5vcm1GKHNoLCB0KTsNCgly
ZXR1cm4gKGNwYWNrbChsb2cxcGwoYXkybCArIHQgKyBzaCkgKiAwLjUsIHYp
KTsNCn0NCg0KI2RlZmluZQlHRU4oZnVuYywgdHlwZSwgbHR5cGUsIHBhcnQs
IGxwYXJ0KQlcDQp0eXBlCQkJCQkJXA0KbHBhcnQgIyMgYyAjIyBmdW5jICMj
IGx0eXBlKHR5cGUgeCwgdHlwZSB5KQlcDQp7CQkJCQkJXA0KCXR5cGUgY29t
cGxleCB6OwkJCQlcDQoJdHlwZSBjb21wbGV4IHc7CQkJCVwNCgkJCQkJCVwN
Cgl6ID0gY3BhY2sgIyMgbHR5cGUoeCwgeSk7CQlcDQoJdyA9IGMgIyMgZnVu
YyAjIyBsdHlwZSh6KTsJCVwNCglyZXR1cm4gKGMgIyMgcGFydCAjIyBsdHlw
ZSh3KSk7CQlcDQp9DQoNCiNkZWZpbmUJR0VOMyhmdW5jKQkJCVwNCkdFTihm
dW5jLCBkb3VibGUsICwgcmVhbCwgcikJCVwNCkdFTihmdW5jLCBkb3VibGUs
ICwgaW1hZywgaSkJCVwNCkdFTihmdW5jLCBmbG9hdCwgZiwgcmVhbCwgcikJ
CVwNCkdFTihmdW5jLCBmbG9hdCwgZiwgaW1hZywgaSkJCVwNCkdFTihmdW5j
LCBsb25nIGRvdWJsZSwgbCwgcmVhbCwgcikJXA0KR0VOKGZ1bmMsIGxvbmcg
ZG91YmxlLCBsLCBpbWFnLCBpKQ0KDQpHRU4zKGFjb3MpDQpHRU4zKGFjb3No
KQ0KR0VOMyhhc2luKQ0KR0VOMyhhc2luaCkNCkdFTjMoYXRhbikNCkdFTjMo
YXRhbmgpDQpHRU4zKGxvZykNCg==

--0-1116022701-1344877047=:3692
Content-Type: TEXT/PLAIN; charset=US-ASCII; name="catrig.diff"
Content-Transfer-Encoding: BASE64
Content-ID: <20120814025727.M3692@besplex.bde.org>
Content-Description: 
Content-Disposition: attachment; filename="catrig.diff"

ZGlmZiAtYzIgY2F0cmlnLmN+IGNhdHJpZy5jDQoqKiogY2F0cmlnLmN+CVN1
biBBdWcgMTIgMTc6Mjk6MTggMjAxMg0KLS0tIGNhdHJpZy5jCU1vbiBBdWcg
MTMgMTI6MDc6MDkgMjAxMg0KKioqKioqKioqKioqKioqDQoqKiogMjY1LDI2
OSAqKioqDQogIAkJcmV0dXJuOw0KICAJfQ0KISAJaWYgKHkgPCBNSU5fNFRI
X1JPT1QpIHsNCiAgCQkvKg0KICAJCSAqIEF2b2lkIGEgcG9zc2libGUgdW5k
ZXJmbG93IGNhdXNlZCBieSB5L0EuICBGb3IgY2FzaW5oIHRoaXMNCi0tLSAy
NjUsMjY5IC0tLS0NCiAgCQlyZXR1cm47DQogIAl9DQohIAlpZiAoIUlTTkFO
KHgpICYmIHkgPCBNSU5fNFRIX1JPT1QpIHsNCiAgCQkvKg0KICAJCSAqIEF2
b2lkIGEgcG9zc2libGUgdW5kZXJmbG93IGNhdXNlZCBieSB5L0EuICBGb3Ig
Y2FzaW5oIHRoaXMNCioqKioqKioqKioqKioqKg0KKioqIDQwOCw0MTYgKioq
Kg0KICANCiAgCWlmIChJU0ZJTklURShieCkgJiYgSVNGSU5JVEUoYnkpICYm
ICh4ID4gUkVDSVBfU1FSVF9FUFNJTE9OXzEwMCB8fCB5ID4gUkVDSVBfU1FS
VF9FUFNJTE9OXzEwMCkpIHsNCiEgCQlpZiAoaHVnZSt4K3k+b25lKSB7IC8q
IHJhaXNlIGluZXhhY3QgZmxhZyAqLw0KISAJCQl3ID0gY2xvZ19mb3JfbGFy
Z2VfdmFsdWVzKHopICsgTV9MTjI7DQogIAkJCWlmIChzeSA9PSAwKQ0KISAJ
CQkJcmV0dXJuIChjcGFjayhjaW1hZyh3KSwgLWNyZWFsKHcpKSk7DQohIAkJ
CXJldHVybiAoY3BhY2soLWNpbWFnKHcpLCBjcmVhbCh3KSkpOw0KICAJCX0N
CiAgCX0NCi0tLSA0MDgsNDIwIC0tLS0NCiAgDQogIAlpZiAoSVNGSU5JVEUo
YngpICYmIElTRklOSVRFKGJ5KSAmJiAoeCA+IFJFQ0lQX1NRUlRfRVBTSUxP
Tl8xMDAgfHwgeSA+IFJFQ0lQX1NRUlRfRVBTSUxPTl8xMDApKSB7DQohIAkJ
LyogWFhYIGZvbGxvd2luZyBjYW4gYWxzbyByYWlzZSBvdmVyZmxvdyAqLw0K
ISAJCWlmIChodWdlK3greT5vbmUpIHsgLyogcmFpc2UgaW5leGFjdCAqLw0K
ISAJCQl3ID0gY2xvZ19mb3JfbGFyZ2VfdmFsdWVzKHopOw0KISAJCQkvKiBD
YW4ndCBhZGQgTV9MTjIgdG8gdyBzaW5jZSBpdCBzaG91bGQgY2xvYmJlciAt
MCpJLiAqLw0KISAJCQlyeCA9IGZhYnMoY2ltYWcodykpOw0KISAJCQlyeSA9
IGNyZWFsKHcpICsgTV9MTjI7DQogIAkJCWlmIChzeSA9PSAwKQ0KISAJCQkJ
cnkgPSAtcnk7DQohIAkJCXJldHVybiAoY3BhY2socngsIHJ5KSk7DQogIAkJ
fQ0KICAJfQ0KKioqKioqKioqKioqKioqDQoqKiogNDgyLDQ4NiAqKioqDQog
IAkgKiBidXQgdGhpcyBjYXNlIHNob3VsZCBoYXBwZW4gZXh0cmVtZWx5IHJh
cmVseS4NCiAgCSAqLw0KISAJaWYgKGF5ID4gMC41KkRCTF9NQVgpDQogIAkJ
cmV0dXJuIChjcGFjayhsb2coaHlwb3QoeCAvIE1fRSwgeSAvIE1fRSkpICsg
MSwgYXRhbjIoeSwgeCkpKTsNCiAgDQotLS0gNDg2LDQ5MCAtLS0tDQogIAkg
KiBidXQgdGhpcyBjYXNlIHNob3VsZCBoYXBwZW4gZXh0cmVtZWx5IHJhcmVs
eS4NCiAgCSAqLw0KISAJaWYgKGF4ID4gMC41KkRCTF9NQVgpDQogIAkJcmV0
dXJuIChjcGFjayhsb2coaHlwb3QoeCAvIE1fRSwgeSAvIE1fRSkpICsgMSwg
YXRhbjIoeSwgeCkpKTsNCiAgDQpkaWZmIC1jMiBjYXRyaWdmLmN+IGNhdHJp
Z2YuYw0KKioqIGNhdHJpZ2YuY34JU3VuIEF1ZyAxMiAxNzowMDo1MiAyMDEy
DQotLS0gY2F0cmlnZi5jCU1vbiBBdWcgMTMgMTQ6MTQ6NDIgMjAxMg0KKioq
KioqKioqKioqKioqDQoqKiogMTM4LDE0MiAqKioqDQogIAkJcmV0dXJuOw0K
ICAJfQ0KISAJaWYgKHkgPCBNSU5fNFRIX1JPT1QpIHsNCiAgCQkqQl9pc191
c2FibGUgPSAwOw0KICAJCWlmICgoaW50KXk9PTApIC8qIHJhaXNlIGluZXhh
Y3QgZmxhZyAqLw0KLS0tIDEzOCwxNDIgLS0tLQ0KICAJCXJldHVybjsNCiAg
CX0NCiEgCWlmICghaXNuYW4oeCkgJiYgeSA8IE1JTl80VEhfUk9PVCkgew0K
ICAJCSpCX2lzX3VzYWJsZSA9IDA7DQogIAkJaWYgKChpbnQpeT09MCkgLyog
cmFpc2UgaW5leGFjdCBmbGFnICovDQoqKioqKioqKioqKioqKioNCioqKiAy
MzMsMjQwICoqKioNCiAgCWlmIChpc2Zpbml0ZSh4KSAmJiBpc2Zpbml0ZSh5
KSAmJiAoeCA+IFJFQ0lQX1NRUlRfRVBTSUxPTl8xMDAgfHwgeSA+IFJFQ0lQ
X1NRUlRfRVBTSUxPTl8xMDApKSB7DQogIAkJaWYgKGh1Z2UreCt5Pm9uZSkg
eyAvKiByYWlzZSBpbmV4YWN0IGZsYWcgKi8NCiEgCQkJdyA9IGNsb2dfZm9y
X2xhcmdlX3ZhbHVlcyh6KSArIE1fTE4yOw0KICAJCQlpZiAoc3kgPT0gMCkN
CiEgCQkJCXJldHVybiAoY3BhY2tmKGNpbWFnZih3KSwgLWNyZWFsZih3KSkp
Ow0KISAJCQlyZXR1cm4gKGNwYWNrZigtY2ltYWdmKHcpLCBjcmVhbGYodykp
KTsNCiAgCQl9DQogIAl9DQotLS0gMjMzLDI0MiAtLS0tDQogIAlpZiAoaXNm
aW5pdGUoeCkgJiYgaXNmaW5pdGUoeSkgJiYgKHggPiBSRUNJUF9TUVJUX0VQ
U0lMT05fMTAwIHx8IHkgPiBSRUNJUF9TUVJUX0VQU0lMT05fMTAwKSkgew0K
ICAJCWlmIChodWdlK3greT5vbmUpIHsgLyogcmFpc2UgaW5leGFjdCBmbGFn
ICovDQohIAkJCXcgPSBjbG9nX2Zvcl9sYXJnZV92YWx1ZXMoeik7DQohIAkJ
CXJ4ID0gZmFic2YoY2ltYWdmKHcpKTsNCiEgCQkJcnkgPSBjcmVhbGYodykg
KyBNX0xOMjsNCiAgCQkJaWYgKHN5ID09IDApDQohIAkJCQlyeSA9IC1yeTsN
CiEgCQkJcmV0dXJuIChjcGFja2YocngsIHJ5KSk7DQogIAkJfQ0KICAJfQ0K
KioqKioqKioqKioqKioqDQoqKiogMjkwLDI5NCAqKioqDQogIAl9DQogIA0K
ISAJaWYgKGF5ID4gMC41KkZMVF9NQVgpDQogIAkJcmV0dXJuIChjcGFja2Yo
bG9nZihoeXBvdGYoeCAvIE1fRSwgeSAvIE1fRSkpICsgMSwgYXRhbjJmKHks
IHgpKSk7DQogIA0KLS0tIDI5MiwyOTYgLS0tLQ0KICAJfQ0KICANCiEgCWlm
IChheCA+IDAuNSpGTFRfTUFYKQ0KICAJCXJldHVybiAoY3BhY2tmKGxvZ2Yo
aHlwb3RmKHggLyBNX0UsIHkgLyBNX0UpKSArIDEsIGF0YW4yZih5LCB4KSkp
Ow0KICANCmRpZmYgLWMyIGNhdHJpZ2wuY34gY2F0cmlnbC5jDQoqKiogY2F0
cmlnbC5jfglTdW4gQXVnIDEyIDA2OjU0OjQ2IDIwMTINCi0tLSBjYXRyaWds
LmMJTW9uIEF1ZyAxMyAxMjowODoyMSAyMDEyDQoqKioqKioqKioqKioqKioN
CioqKiAxMTksMTIzICoqKioNCiAgCQlyZXR1cm47DQogIAl9DQohIAlpZiAo
eSA8IE1JTl80VEhfUk9PVCkgew0KICAJCSpCX2lzX3VzYWJsZSA9IDA7DQog
IAkJaWYgKChpbnQpeT09MCkgLyogcmFpc2UgaW5leGFjdCBmbGFnICovDQot
LS0gMTE5LDEyMyAtLS0tDQogIAkJcmV0dXJuOw0KICAJfQ0KISAJaWYgKCFp
c25hbih4KSAmJiB5IDwgTUlOXzRUSF9ST09UKSB7DQogIAkJKkJfaXNfdXNh
YmxlID0gMDsNCiAgCQlpZiAoKGludCl5PT0wKSAvKiByYWlzZSBpbmV4YWN0
IGZsYWcgKi8NCioqKioqKioqKioqKioqKg0KKioqIDIwNywyMTQgKioqKg0K
ICAJaWYgKGlzZmluaXRlKHgpICYmIGlzZmluaXRlKHkpICYmICh4ID4gUkVD
SVBfU1FSVF9FUFNJTE9OXzEwMCB8fCB5ID4gUkVDSVBfU1FSVF9FUFNJTE9O
XzEwMCkpIHsNCiAgCQlpZiAoaHVnZSt4K3k+b25lKSB7IC8qIHJhaXNlIGlu
ZXhhY3QgZmxhZyAqLw0KISAJCQl3ID0gY2xvZ19mb3JfbGFyZ2VfdmFsdWVz
KHopICsgTF9MTjI7DQogIAkJCWlmIChzeSA9PSAwKQ0KISAJCQkJcmV0dXJu
IChjcGFja2woY2ltYWdsKHcpLCAtY3JlYWxsKHcpKSk7DQohIAkJCXJldHVy
biAoY3BhY2tsKC1jaW1hZ2wodyksIGNyZWFsbCh3KSkpOw0KICAJCX0NCiAg
CX0NCi0tLSAyMDcsMjE2IC0tLS0NCiAgCWlmIChpc2Zpbml0ZSh4KSAmJiBp
c2Zpbml0ZSh5KSAmJiAoeCA+IFJFQ0lQX1NRUlRfRVBTSUxPTl8xMDAgfHwg
eSA+IFJFQ0lQX1NRUlRfRVBTSUxPTl8xMDApKSB7DQogIAkJaWYgKGh1Z2Ur
eCt5Pm9uZSkgeyAvKiByYWlzZSBpbmV4YWN0IGZsYWcgKi8NCiEgCQkJdyA9
IGNsb2dfZm9yX2xhcmdlX3ZhbHVlcyh6KTsNCiEgCQkJcnggPSBmYWJzbChj
aW1hZ2wodykpOw0KISAJCQlyeSA9IGNyZWFsbCh3KSArIE1fTE4yOw0KICAJ
CQlpZiAoc3kgPT0gMCkNCiEgCQkJCXJ5ID0gLXJ5Ow0KISAJCQlyZXR1cm4g
KGNwYWNrbChyeCwgcnkpKTsNCiAgCQl9DQogIAl9DQoqKioqKioqKioqKioq
KioNCioqKiAyNjQsMjY4ICoqKioNCiAgCX0NCiAgDQohIAlpZiAoYXkgPiAw
LjUqTERCTF9NQVgpDQogIAkJcmV0dXJuIChjcGFja2wobG9nbChoeXBvdGwo
eCAvIExfRSwgeSAvIExfRSkpICsgMSwgYXRhbjJsKHksIHgpKSk7DQogIA0K
LS0tIDI2NiwyNzAgLS0tLQ0KICAJfQ0KICANCiEgCWlmIChheCA+IDAuNSpM
REJMX01BWCkNCiAgCQlyZXR1cm4gKGNwYWNrbChsb2dsKGh5cG90bCh4IC8g
TF9FLCB5IC8gTF9FKSkgKyAxLCBhdGFuMmwoeSwgeCkpKTsNCiAgDQo=

--0-1116022701-1344877047=:3692--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120814003614.H3692>