#include <stdio.h>
#include <math.h>
int get_polynomial_degree( int polynomial_degree) ;
void get_polynomial_coefficients( int polynomial_degree, double polynomial_coefficients[ ] ) ;
int get_possible_roots_size( int polynomial_degree, double polynomial_coefficients[ ] ) ;
void get_possible_roots( int polynomial_degree, double polynomial_coefficients[ ] , double possible_roots[ ] , int a0_over_an_size) ;
int get_number_of_factors_a0( double polynomial_coefficients[ ] ) ;
int get_number_of_factors_an( int polynomial_degree, double polynomial_coefficients[ ] ) ;
void get_factors_a0( double polynomial_coefficients[ ] , int factors_a0[ ] ) ;
void get_factors_an( int polynomial_degree, double polynomial_coefficients[ ] , int factors_an[ ] ) ;
int get_a0_over_an_size( int num_factors_a0, int num_factors_an, int factors_a0[ ] , int factors_an[ ] ) ;
void get_a0_over_an( int p_numerator[ ] , int p_denominator[ ] , int factors_a0[ ] , int factors_an[ ] , int num_factors_a0, int num_factors_an) ;
int get_gcd( int num1, int num2) ;
int get_rational_roots_size( int polynomial_degree, double polynomial_coefficients[ ] , double possible_roots[ ] , int num_possible_roots) ;
void get_rational_roots( int polynomial_degree, double polynomial_coefficients[ ] , double possible_roots[ ] , int num_possible_roots, double rational_roots[ ] ) ;
int main( )
{
int i;
int polynomial_degree = get_polynomial_degree( polynomial_degree) ;
double polynomial_coefficients[ polynomial_degree] ;
get_polynomial_coefficients( polynomial_degree, polynomial_coefficients) ;
int num_possible_roots = 2 * get_possible_roots_size( polynomial_degree, polynomial_coefficients) ;
double possible_roots[ num_possible_roots] ;
get_possible_roots( polynomial_degree, polynomial_coefficients, possible_roots, num_possible_roots) ;
printf ( "The input degree is: %d\n " , polynomial_degree
) ; printf ( "The input coefficients are: " ) ; for ( i = 0 ; i < polynomial_degree+ 1 ; i++ )
{
printf ( "%0.4lf " , polynomial_coefficients
[ i
] ) ; }
printf ( "There are %d possible_roots." , num_possible_roots
) ; printf ( "The possible roots are: \n " ) ; for ( i = 0 ; i < num_possible_roots; i++ )
{
printf ( "%0.4lf \n " , possible_roots
[ i
] ) ; }
int num_rational_roots = get_rational_roots_size( polynomial_degree, polynomial_coefficients, possible_roots, num_possible_roots) ;
double rational_roots[ num_rational_roots] ;
get_rational_roots( polynomial_degree, polynomial_coefficients, possible_roots, num_possible_roots, rational_roots) ;
if ( num_rational_roots >= 1 )
{
printf ( "The number of rational roots is: %d\n " , num_rational_roots
) ; for ( i = 0 ; i < num_rational_roots; i++ )
{
printf ( "%0.4lf " , rational_roots
[ i
] ) ; }
}
else if ( num_rational_roots == 0 )
{
printf ( "There are no rational roots for this input.\n " ) ; }
return 0 ;
}
int get_polynomial_degree( int polynomial_degree)
{
printf ( "Enter the highest degree of the input polynomial: \n " ) ; scanf ( "%d" , & polynomial_degree
) ;
return polynomial_degree;
}
void get_polynomial_coefficients( int polynomial_degree, double polynomial_coefficients[ ] )
{
int i;
printf ( "Enter %d integer coefficients starting from 0th degree.\n " , polynomial_degree
+ 1 ) ; printf ( "Separate each input by a comma: \n " ) ; for ( i = 0 ; i <= polynomial_degree; i++ )
{
scanf ( "%lf, " , & polynomial_coefficients
[ i
] ) ; }
}
int get_possible_roots_size( int polynomial_degree, double polynomial_coefficients[ ] )
{
int num_factors_a0, num_factors_an;
num_factors_a0 = get_number_of_factors_a0( polynomial_coefficients) ;
num_factors_an = get_number_of_factors_an( polynomial_degree, polynomial_coefficients) ;
int factors_a0[ num_factors_a0] , factors_an[ num_factors_an] ;
get_factors_a0( polynomial_coefficients, factors_a0) ;
get_factors_an( polynomial_degree, polynomial_coefficients, factors_an) ;
int i, j, gcd, size = num_factors_a0 * num_factors_an;
for ( i = 0 ; i < num_factors_a0; i++ )
{
for ( j = 0 ; j < num_factors_an; j++ )
{
gcd = get_gcd( factors_a0[ i] , factors_an[ j] ) ;
if ( gcd != 1 )
{
size--;
}
}
}
return size;
}
void get_possible_roots( int polynomial_degree, double polynomial_coefficients[ ] , double possible_roots[ ] , int a0_over_an_size)
{
int num_factors_a0, num_factors_an;
num_factors_a0 = get_number_of_factors_a0( polynomial_coefficients) ;
num_factors_an = get_number_of_factors_an( polynomial_degree, polynomial_coefficients) ;
int factors_a0[ num_factors_a0] , factors_an[ num_factors_an] ;
get_factors_a0( polynomial_coefficients, factors_a0) ;
get_factors_an( polynomial_degree, polynomial_coefficients, factors_an) ;
a0_over_an_size = get_a0_over_an_size( num_factors_a0, num_factors_an, factors_a0, factors_an) ;
int p_numerator[ a0_over_an_size] , p_denominator[ a0_over_an_size] ;
get_a0_over_an( p_numerator, p_denominator, factors_a0, factors_an, num_factors_a0, num_factors_an) ;
int i;
for ( i = 0 ; i < a0_over_an_size; i++ )
{
possible_roots[ i * 2 ] = ( double ) p_numerator[ i] / ( double ) p_denominator[ i] ;
possible_roots[ i * 2 + 1 ] = - ( double ) p_numerator[ i] / ( double ) p_denominator[ i] ;
}
}
int get_number_of_factors_a0( double polynomial_coefficients[ ] )
{
int divisorCount = 1 , i;
int abs_polynomial_coefficients_0 = polynomial_coefficients[ 0 ] ;
abs_polynomial_coefficients_0
= fabs ( abs_polynomial_coefficients_0
) ;
if ( abs_polynomial_coefficients_0 == 0 || abs_polynomial_coefficients_0 == 1 )
{
return divisorCount;
}
else
{
for ( i = 2 ; i * i < ( int ) abs_polynomial_coefficients_0; ++ i)
{
if ( ( int ) abs_polynomial_coefficients_0 % i == 0 )
{
++ divisorCount;
}
}
divisorCount *= 2 ;
if ( i * i == ( int ) abs_polynomial_coefficients_0)
{
++ divisorCount;
}
return divisorCount;
}
}
int get_number_of_factors_an( int polynomial_degree, double polynomial_coefficients[ ] )
{
int divisorCount = 1 , i;
int abs_polynomial_coefficients_n = polynomial_coefficients[ polynomial_degree] ;
abs_polynomial_coefficients_n
= fabs ( abs_polynomial_coefficients_n
) ;
if ( abs_polynomial_coefficients_n == 0 || abs_polynomial_coefficients_n == 1 )
{
return divisorCount;
}
else
{
for ( i = 2 ; i * i < ( int ) abs_polynomial_coefficients_n; ++ i)
{
if ( ( int ) abs_polynomial_coefficients_n % i == 0 )
{
++ divisorCount;
}
}
divisorCount *= 2 ;
if ( i * i == ( int ) abs_polynomial_coefficients_n)
{
++ divisorCount;
}
return divisorCount;
}
}
void get_factors_a0( double polynomial_coefficients[ ] , int factors_a0[ ] )
{
int i, element = 0 ;
int abs_polynomial_coefficients_0 = polynomial_coefficients[ 0 ] ;
abs_polynomial_coefficients_0
= fabs ( abs_polynomial_coefficients_0
) ;
if ( abs_polynomial_coefficients_0 == 0 )
{
factors_a0[ 0 ] = 0 ;
}
else
{
for ( i= 1 ; i<= ( int ) abs_polynomial_coefficients_0; ++ i)
{
if ( ( int ) abs_polynomial_coefficients_0% i== 0 )
{
factors_a0[ element] = i;
element++;
}
}
}
}
void get_factors_an( int polynomial_degree, double polynomial_coefficients[ ] , int factors_an[ ] )
{
int i, element = 0 ;
int abs_polynomial_coefficients_n = polynomial_coefficients[ polynomial_degree] ;
abs_polynomial_coefficients_n
= fabs ( abs_polynomial_coefficients_n
) ; if ( abs_polynomial_coefficients_n == 0 )
{
factors_an[ 0 ] = 0 ;
}
else
{
for ( i= 1 ; i<= ( int ) abs_polynomial_coefficients_n;++ i)
{
if ( ( int ) abs_polynomial_coefficients_n% i== 0 )
{
factors_an[ element] = i;
element++;
}
}
}
}
int get_a0_over_an_size( int num_factors_a0, int num_factors_an, int factors_a0[ ] , int factors_an[ ] )
{
int i, j, gcd, size = num_factors_a0 * num_factors_an;
for ( i = 0 ; i < num_factors_a0; i++ )
{
for ( j = 0 ; j < num_factors_an; j++ )
{
gcd = get_gcd( factors_a0[ i] , factors_an[ j] ) ;
if ( gcd != 1 )
{
size--;
}
}
}
return size;
}
void get_a0_over_an( int p_numerator[ ] , int p_denominator[ ] , int factors_a0[ ] , int factors_an[ ] , int num_factors_a0, int num_factors_an)
{
int i, j, gcd, element = 0 ;
for ( i = 0 ; i < num_factors_a0; i++ )
{
for ( j = 0 ; j < num_factors_an; j++ )
{
gcd = get_gcd( factors_a0[ i] , factors_an[ j] ) ;
if ( gcd == 1 )
{
p_numerator[ element] = factors_a0[ i] ;
p_denominator[ element] = factors_an[ j] ;
element++;
}
}
}
}
int get_gcd( int num1, int num2)
{
while ( num1!= num2)
{
if ( num1> num2)
num1-= num2;
else
num2-= num1;
}
return num1;
}
int get_rational_roots_size( int polynomial_degree, double polynomial_coefficients[ ] , double possible_roots[ ] , int num_possible_roots)
{
int i, j, num_rational_roots = 0 ;
double quotient_coefficients[ polynomial_degree] ;
quotient_coefficients[ 0 ] = polynomial_coefficients[ polynomial_degree] ;
for ( i = 0 ; i < num_possible_roots; i++ )
{
for ( j= 1 ; j<= polynomial_degree; j++ )
{
quotient_coefficients[ j] = ( quotient_coefficients[ j- 1 ] * possible_roots[ i] ) + polynomial_coefficients[ polynomial_degree- j] ;
if ( quotient_coefficients[ 2 ] == 0 && j == 2 )
{
num_rational_roots++;
}
}
}
return num_rational_roots;
}
void get_rational_roots( int polynomial_degree, double polynomial_coefficients[ ] , double possible_roots[ ] , int num_possible_roots, double rational_roots[ ] )
{
int i, j, element = 0 ;
double quotient_coefficients[ polynomial_degree] ;
quotient_coefficients[ 0 ] = polynomial_coefficients[ polynomial_degree] ;
for ( i = 0 ; i < num_possible_roots; i++ )
{
for ( j= 1 ; j<= polynomial_degree; j++ )
{
quotient_coefficients[ j] = ( quotient_coefficients[ j- 1 ] * possible_roots[ i] ) + polynomial_coefficients[ polynomial_degree- j] ;
printf ( "Result %d = %lf\t " , j
, quotient_coefficients
[ j
] ) ; if ( quotient_coefficients[ 2 ] == + 0 || quotient_coefficients[ 2 ] == - 0 )
{
rational_roots[ element] = possible_roots[ i] ;
printf ( "\n Root %lf at i = %d, j = %d\n " , rational_roots
[ element
] , i
, j
) ; element++;
}
}
}
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxtYXRoLmg+CmludAkgZ2V0X3BvbHlub21pYWxfZGVncmVlKGludCBwb2x5bm9taWFsX2RlZ3JlZSk7CnZvaWQJIGdldF9wb2x5bm9taWFsX2NvZWZmaWNpZW50cyhpbnQgcG9seW5vbWlhbF9kZWdyZWUsIGRvdWJsZSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1tdKTsKCmludCAgZ2V0X3Bvc3NpYmxlX3Jvb3RzX3NpemUoaW50IHBvbHlub21pYWxfZGVncmVlLCBkb3VibGUgcG9seW5vbWlhbF9jb2VmZmljaWVudHNbXSk7CnZvaWQgZ2V0X3Bvc3NpYmxlX3Jvb3RzKGludCBwb2x5bm9taWFsX2RlZ3JlZSwgZG91YmxlIHBvbHlub21pYWxfY29lZmZpY2llbnRzW10sIGRvdWJsZSBwb3NzaWJsZV9yb290c1tdLCBpbnQgYTBfb3Zlcl9hbl9zaXplKTsKaW50IAkJZ2V0X251bWJlcl9vZl9mYWN0b3JzX2EwKGRvdWJsZSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1tdKTsKaW50IAkJZ2V0X251bWJlcl9vZl9mYWN0b3JzX2FuKGludCBwb2x5bm9taWFsX2RlZ3JlZSwgZG91YmxlIHBvbHlub21pYWxfY29lZmZpY2llbnRzW10pOwp2b2lkCQlnZXRfZmFjdG9yc19hMChkb3VibGUgcG9seW5vbWlhbF9jb2VmZmljaWVudHNbXSwgaW50IGZhY3RvcnNfYTBbXSk7CnZvaWQgCQlnZXRfZmFjdG9yc19hbihpbnQgcG9seW5vbWlhbF9kZWdyZWUsIGRvdWJsZSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1tdLCBpbnQgZmFjdG9yc19hbltdKTsKaW50IAkJZ2V0X2EwX292ZXJfYW5fc2l6ZShpbnQgbnVtX2ZhY3RvcnNfYTAsIGludCBudW1fZmFjdG9yc19hbiwgaW50IGZhY3RvcnNfYTBbXSwgaW50IGZhY3RvcnNfYW5bXSk7CnZvaWQgCQlnZXRfYTBfb3Zlcl9hbihpbnQgcF9udW1lcmF0b3JbXSwgaW50IHBfZGVub21pbmF0b3JbXSwgaW50IGZhY3RvcnNfYTBbXSwgaW50IGZhY3RvcnNfYW5bXSwgaW50IG51bV9mYWN0b3JzX2EwLCBpbnQgbnVtX2ZhY3RvcnNfYW4pOwppbnQgCQlnZXRfZ2NkKGludCBudW0xLCBpbnQgbnVtMik7CgppbnQgIGdldF9yYXRpb25hbF9yb290c19zaXplKGludCBwb2x5bm9taWFsX2RlZ3JlZSwgZG91YmxlIHBvbHlub21pYWxfY29lZmZpY2llbnRzW10sIGRvdWJsZSBwb3NzaWJsZV9yb290c1tdLCBpbnQgbnVtX3Bvc3NpYmxlX3Jvb3RzKTsKdm9pZCBnZXRfcmF0aW9uYWxfcm9vdHMoaW50IHBvbHlub21pYWxfZGVncmVlLCBkb3VibGUgcG9seW5vbWlhbF9jb2VmZmljaWVudHNbXSwgZG91YmxlIHBvc3NpYmxlX3Jvb3RzW10sIGludCBudW1fcG9zc2libGVfcm9vdHMsIGRvdWJsZSByYXRpb25hbF9yb290c1tdKTsKCgoKaW50IG1haW4oKQp7CglpbnQgaTsKCQoJaW50IHBvbHlub21pYWxfZGVncmVlID0gZ2V0X3BvbHlub21pYWxfZGVncmVlKHBvbHlub21pYWxfZGVncmVlKTsKCWRvdWJsZSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1twb2x5bm9taWFsX2RlZ3JlZV07CglnZXRfcG9seW5vbWlhbF9jb2VmZmljaWVudHMocG9seW5vbWlhbF9kZWdyZWUsIHBvbHlub21pYWxfY29lZmZpY2llbnRzKTsKCQoJaW50IG51bV9wb3NzaWJsZV9yb290cyA9IDIgKiBnZXRfcG9zc2libGVfcm9vdHNfc2l6ZShwb2x5bm9taWFsX2RlZ3JlZSwgcG9seW5vbWlhbF9jb2VmZmljaWVudHMpOwoJZG91YmxlIHBvc3NpYmxlX3Jvb3RzW251bV9wb3NzaWJsZV9yb290c107CglnZXRfcG9zc2libGVfcm9vdHMocG9seW5vbWlhbF9kZWdyZWUsIHBvbHlub21pYWxfY29lZmZpY2llbnRzLCBwb3NzaWJsZV9yb290cywgbnVtX3Bvc3NpYmxlX3Jvb3RzKTsKCQoJCglwcmludGYoIlRoZSBpbnB1dCBkZWdyZWUgaXM6ICVkXG4iLCBwb2x5bm9taWFsX2RlZ3JlZSk7CglwcmludGYoIlRoZSBpbnB1dCBjb2VmZmljaWVudHMgYXJlOiAiKTsKCWZvcihpID0gMDsgaSA8IHBvbHlub21pYWxfZGVncmVlKzE7IGkrKykKCXsKCQlwcmludGYoIiUwLjRsZiAiLCBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1tpXSk7Cgl9CglwcmludGYoIlxuIik7CgoJCglwcmludGYoIlRoZXJlIGFyZSAlZCBwb3NzaWJsZV9yb290cy4iLCBudW1fcG9zc2libGVfcm9vdHMpOwoJcHJpbnRmKCJUaGUgcG9zc2libGUgcm9vdHMgYXJlOiBcbiIpOwoJZm9yKGkgPSAwOyBpIDwgbnVtX3Bvc3NpYmxlX3Jvb3RzOyBpKyspCgl7CgkJcHJpbnRmKCIlMC40bGYgXG4iLCBwb3NzaWJsZV9yb290c1tpXSk7Cgl9CglwcmludGYoIlxuIik7IAkKCQoJaW50IG51bV9yYXRpb25hbF9yb290cyA9IGdldF9yYXRpb25hbF9yb290c19zaXplKHBvbHlub21pYWxfZGVncmVlLCBwb2x5bm9taWFsX2NvZWZmaWNpZW50cywgcG9zc2libGVfcm9vdHMsIG51bV9wb3NzaWJsZV9yb290cyk7Cglkb3VibGUgcmF0aW9uYWxfcm9vdHNbbnVtX3JhdGlvbmFsX3Jvb3RzXTsKCWdldF9yYXRpb25hbF9yb290cyhwb2x5bm9taWFsX2RlZ3JlZSwgcG9seW5vbWlhbF9jb2VmZmljaWVudHMsIHBvc3NpYmxlX3Jvb3RzLCBudW1fcG9zc2libGVfcm9vdHMsIHJhdGlvbmFsX3Jvb3RzKTsKCQoJaWYobnVtX3JhdGlvbmFsX3Jvb3RzID49IDEpCgl7CgkJcHJpbnRmKCJUaGUgbnVtYmVyIG9mIHJhdGlvbmFsIHJvb3RzIGlzOiAlZFxuIiwgbnVtX3JhdGlvbmFsX3Jvb3RzKTsKCQlwcmludGYoIlJvb3QvcyBhcmU6ICIpOwoJCWZvcihpID0gMDsgaSA8IG51bV9yYXRpb25hbF9yb290czsgaSsrKQoJCXsKCQkJcHJpbnRmKCIlMC40bGYgIiwgcmF0aW9uYWxfcm9vdHNbaV0pOwoJCX0KCX0KCWVsc2UgaWYobnVtX3JhdGlvbmFsX3Jvb3RzID09IDApCgl7CgkJcHJpbnRmKCJUaGVyZSBhcmUgbm8gcmF0aW9uYWwgcm9vdHMgZm9yIHRoaXMgaW5wdXQuXG4iKTsKCX0KCQoJCglyZXR1cm4gMDsKfQoKaW50IGdldF9wb2x5bm9taWFsX2RlZ3JlZShpbnQgcG9seW5vbWlhbF9kZWdyZWUpCnsKCXByaW50ZigiRW50ZXIgdGhlIGhpZ2hlc3QgZGVncmVlIG9mIHRoZSBpbnB1dCBwb2x5bm9taWFsOiBcbiIpOwoJc2NhbmYoIiVkIiwgJnBvbHlub21pYWxfZGVncmVlKTsKCQoJcmV0dXJuIHBvbHlub21pYWxfZGVncmVlOwp9Cgp2b2lkIGdldF9wb2x5bm9taWFsX2NvZWZmaWNpZW50cyhpbnQgcG9seW5vbWlhbF9kZWdyZWUsIGRvdWJsZSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1tdKQp7CglpbnQgaTsKCQoJcHJpbnRmKCJFbnRlciAlZCBpbnRlZ2VyIGNvZWZmaWNpZW50cyBzdGFydGluZyBmcm9tIDB0aCBkZWdyZWUuXG4iLCBwb2x5bm9taWFsX2RlZ3JlZSsxKTsKCXByaW50ZigiU2VwYXJhdGUgZWFjaCBpbnB1dCBieSBhIGNvbW1hOiBcbiIpOwoJZm9yKGkgPSAwO2kgPD0gcG9seW5vbWlhbF9kZWdyZWU7IGkrKykKCXsKCQlzY2FuZigiJWxmLCAiLCAmcG9seW5vbWlhbF9jb2VmZmljaWVudHNbaV0pOwoJfQp9CgppbnQgZ2V0X3Bvc3NpYmxlX3Jvb3RzX3NpemUoaW50IHBvbHlub21pYWxfZGVncmVlLCBkb3VibGUgcG9seW5vbWlhbF9jb2VmZmljaWVudHNbXSkKewoJaW50IG51bV9mYWN0b3JzX2EwLCBudW1fZmFjdG9yc19hbjsKCW51bV9mYWN0b3JzX2EwID0gZ2V0X251bWJlcl9vZl9mYWN0b3JzX2EwKHBvbHlub21pYWxfY29lZmZpY2llbnRzKTsKCW51bV9mYWN0b3JzX2FuID0gZ2V0X251bWJlcl9vZl9mYWN0b3JzX2FuKHBvbHlub21pYWxfZGVncmVlLCBwb2x5bm9taWFsX2NvZWZmaWNpZW50cyk7CgkKCWludCBmYWN0b3JzX2EwW251bV9mYWN0b3JzX2EwXSwgZmFjdG9yc19hbltudW1fZmFjdG9yc19hbl07CglnZXRfZmFjdG9yc19hMChwb2x5bm9taWFsX2NvZWZmaWNpZW50cywgZmFjdG9yc19hMCk7CglnZXRfZmFjdG9yc19hbihwb2x5bm9taWFsX2RlZ3JlZSwgcG9seW5vbWlhbF9jb2VmZmljaWVudHMsIGZhY3RvcnNfYW4pOwoKCWludCBpLCBqLCBnY2QsIHNpemUgPSBudW1fZmFjdG9yc19hMCAqIG51bV9mYWN0b3JzX2FuOwoJZm9yKGkgPSAwOyBpIDwgbnVtX2ZhY3RvcnNfYTA7aSsrKQoJewoJCWZvcihqID0gMDsgaiA8IG51bV9mYWN0b3JzX2FuO2orKykKCQl7CgkJCWdjZCA9IGdldF9nY2QoZmFjdG9yc19hMFtpXSwgZmFjdG9yc19hbltqXSk7CgkJCWlmKGdjZCAhPSAxKQoJCQl7CgkJCQlzaXplLS07CgkJCX0KCQl9Cgl9CglyZXR1cm4gc2l6ZTsKfQoKdm9pZCBnZXRfcG9zc2libGVfcm9vdHMoaW50IHBvbHlub21pYWxfZGVncmVlLCBkb3VibGUgcG9seW5vbWlhbF9jb2VmZmljaWVudHNbXSwgZG91YmxlIHBvc3NpYmxlX3Jvb3RzW10sIGludCBhMF9vdmVyX2FuX3NpemUpCnsKCWludCBudW1fZmFjdG9yc19hMCwgbnVtX2ZhY3RvcnNfYW47CgludW1fZmFjdG9yc19hMCA9IGdldF9udW1iZXJfb2ZfZmFjdG9yc19hMChwb2x5bm9taWFsX2NvZWZmaWNpZW50cyk7CgludW1fZmFjdG9yc19hbiA9IGdldF9udW1iZXJfb2ZfZmFjdG9yc19hbihwb2x5bm9taWFsX2RlZ3JlZSwgcG9seW5vbWlhbF9jb2VmZmljaWVudHMpOwoJCglpbnQgZmFjdG9yc19hMFtudW1fZmFjdG9yc19hMF0sIGZhY3RvcnNfYW5bbnVtX2ZhY3RvcnNfYW5dOwoJZ2V0X2ZhY3RvcnNfYTAocG9seW5vbWlhbF9jb2VmZmljaWVudHMsIGZhY3RvcnNfYTApOwoJZ2V0X2ZhY3RvcnNfYW4ocG9seW5vbWlhbF9kZWdyZWUsIHBvbHlub21pYWxfY29lZmZpY2llbnRzLCBmYWN0b3JzX2FuKTsKCQoJYTBfb3Zlcl9hbl9zaXplID0gZ2V0X2EwX292ZXJfYW5fc2l6ZShudW1fZmFjdG9yc19hMCwgbnVtX2ZhY3RvcnNfYW4sIGZhY3RvcnNfYTAsIGZhY3RvcnNfYW4pOwoJaW50IHBfbnVtZXJhdG9yW2EwX292ZXJfYW5fc2l6ZV0sIHBfZGVub21pbmF0b3JbYTBfb3Zlcl9hbl9zaXplXTsKCWdldF9hMF9vdmVyX2FuKHBfbnVtZXJhdG9yLCBwX2Rlbm9taW5hdG9yLCBmYWN0b3JzX2EwLCBmYWN0b3JzX2FuLCBudW1fZmFjdG9yc19hMCwgbnVtX2ZhY3RvcnNfYW4pOwkKCgogICAgaW50IGk7CiAgICBmb3IgKGkgPSAwOyBpIDwgYTBfb3Zlcl9hbl9zaXplOyBpKyspCiAgICB7CiAgICAgICAgcG9zc2libGVfcm9vdHNbaSAqIDJdID0gKGRvdWJsZSlwX251bWVyYXRvcltpXS8oZG91YmxlKXBfZGVub21pbmF0b3JbaV07CiAgICAgICAgcG9zc2libGVfcm9vdHNbaSAqIDIgKyAxXSA9IC0oZG91YmxlKXBfbnVtZXJhdG9yW2ldLyhkb3VibGUpcF9kZW5vbWluYXRvcltpXTsKICAgIH0KfQoKaW50IGdldF9udW1iZXJfb2ZfZmFjdG9yc19hMChkb3VibGUgcG9seW5vbWlhbF9jb2VmZmljaWVudHNbXSkKewoJaW50IGRpdmlzb3JDb3VudCA9IDEsIGk7CglpbnQgYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzXzAgPSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1swXTsKCWFic19wb2x5bm9taWFsX2NvZWZmaWNpZW50c18wID0gZmFicyhhYnNfcG9seW5vbWlhbF9jb2VmZmljaWVudHNfMCk7CgkKCWlmKGFic19wb2x5bm9taWFsX2NvZWZmaWNpZW50c18wID09IDAgfHwgYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzXzAgPT0gMSkKCXsKCQlyZXR1cm4gZGl2aXNvckNvdW50OwoJfQoJZWxzZQoJewoJCWZvcihpID0gMjsgaSAqIGkgPCAoaW50KWFic19wb2x5bm9taWFsX2NvZWZmaWNpZW50c18wOyArK2kpCgkJewoJCQlpZigoaW50KWFic19wb2x5bm9taWFsX2NvZWZmaWNpZW50c18wICUgaSA9PSAwKQoJCQl7CgkJCQkrK2Rpdmlzb3JDb3VudDsKCQkJfQoJCX0KCQlkaXZpc29yQ291bnQgKj0gMjsKCQlpZihpICogaSA9PSAoaW50KWFic19wb2x5bm9taWFsX2NvZWZmaWNpZW50c18wKQoJCXsKCQkJKytkaXZpc29yQ291bnQ7CgkJfQoJCXJldHVybiBkaXZpc29yQ291bnQ7Cgl9Cn0KCmludCBnZXRfbnVtYmVyX29mX2ZhY3RvcnNfYW4oaW50IHBvbHlub21pYWxfZGVncmVlLCBkb3VibGUgcG9seW5vbWlhbF9jb2VmZmljaWVudHNbXSkKewoJaW50IGRpdmlzb3JDb3VudCA9IDEsIGk7CglpbnQgYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzX24gPSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1twb2x5bm9taWFsX2RlZ3JlZV07CglhYnNfcG9seW5vbWlhbF9jb2VmZmljaWVudHNfbiA9IGZhYnMoYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzX24pOwoJCglpZihhYnNfcG9seW5vbWlhbF9jb2VmZmljaWVudHNfbiA9PSAwIHx8IGFic19wb2x5bm9taWFsX2NvZWZmaWNpZW50c19uID09IDEpCgl7CgkJcmV0dXJuIGRpdmlzb3JDb3VudDsKCX0KCWVsc2UKCXsKCQlmb3IoaSA9IDI7IGkgKiBpIDwgKGludClhYnNfcG9seW5vbWlhbF9jb2VmZmljaWVudHNfbjsgKytpKQoJCXsKCQkJaWYoKGludClhYnNfcG9seW5vbWlhbF9jb2VmZmljaWVudHNfbiAlIGkgPT0gMCkKCQkJewoJCQkJKytkaXZpc29yQ291bnQ7CgkJCX0KCQl9CgkJZGl2aXNvckNvdW50ICo9IDI7CgkJaWYoaSAqIGkgPT0gKGludClhYnNfcG9seW5vbWlhbF9jb2VmZmljaWVudHNfbikKCQl7CgkJCSsrZGl2aXNvckNvdW50OwoJCX0KCQlyZXR1cm4gZGl2aXNvckNvdW50OwoJfQp9Cgp2b2lkIGdldF9mYWN0b3JzX2EwKGRvdWJsZSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1tdLCBpbnQgZmFjdG9yc19hMFtdKQp7CglpbnQgaSwgZWxlbWVudCA9IDA7CglpbnQgYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzXzAgPSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1swXTsKCWFic19wb2x5bm9taWFsX2NvZWZmaWNpZW50c18wID0gZmFicyhhYnNfcG9seW5vbWlhbF9jb2VmZmljaWVudHNfMCk7CgkKCWlmKGFic19wb2x5bm9taWFsX2NvZWZmaWNpZW50c18wID09IDApCgl7CgkJZmFjdG9yc19hMFswXSA9IDA7Cgl9CgllbHNlCgl7CgkJZm9yKGk9MTsgaTw9IChpbnQpYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzXzA7ICsraSkKCQl7CgkJCWlmKChpbnQpYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzXzAlaT09MCkKCQkJewoJCQkJCgkJCQlmYWN0b3JzX2EwW2VsZW1lbnRdID0gaTsKCQkJCWVsZW1lbnQrKzsKCQkJfQoJCX0KCX0KfQoKdm9pZCBnZXRfZmFjdG9yc19hbihpbnQgcG9seW5vbWlhbF9kZWdyZWUsIGRvdWJsZSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1tdLCBpbnQgZmFjdG9yc19hbltdKQp7CglpbnQgaSwgZWxlbWVudCA9IDA7CglpbnQgYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzX24gPSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1twb2x5bm9taWFsX2RlZ3JlZV07CglhYnNfcG9seW5vbWlhbF9jb2VmZmljaWVudHNfbiA9IGZhYnMoYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzX24pOwoJaWYoYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzX24gPT0gMCkKCXsKCQlmYWN0b3JzX2FuWzBdID0gMDsKCX0KCWVsc2UKCXsKCQlmb3IoaT0xO2k8PShpbnQpYWJzX3BvbHlub21pYWxfY29lZmZpY2llbnRzX247KytpKQoJICB7CgkJICBpZigoaW50KWFic19wb2x5bm9taWFsX2NvZWZmaWNpZW50c19uJWk9PTApCgkJICB7CgkJCQkKCQkJCWZhY3RvcnNfYW5bZWxlbWVudF0gPSBpOwoJCQkJZWxlbWVudCsrOwoJCSAgfQoJICB9Cgl9Cn0KCmludCBnZXRfYTBfb3Zlcl9hbl9zaXplKGludCBudW1fZmFjdG9yc19hMCwgaW50IG51bV9mYWN0b3JzX2FuLCBpbnQgZmFjdG9yc19hMFtdLCBpbnQgZmFjdG9yc19hbltdKQp7CglpbnQgaSwgaiwgZ2NkLCBzaXplID0gbnVtX2ZhY3RvcnNfYTAgKiBudW1fZmFjdG9yc19hbjsKCWZvcihpID0gMDsgaSA8IG51bV9mYWN0b3JzX2EwO2krKykKCXsKCQlmb3IoaiA9IDA7IGogPCBudW1fZmFjdG9yc19hbjtqKyspCgkJewoJCQlnY2QgPSBnZXRfZ2NkKGZhY3RvcnNfYTBbaV0sIGZhY3RvcnNfYW5bal0pOwoJCQlpZihnY2QgIT0gMSkKCQkJewoJCQkJc2l6ZS0tOwoJCQl9CgkJfQoJfQoJcmV0dXJuIHNpemU7Cn0KCnZvaWQgZ2V0X2EwX292ZXJfYW4oaW50IHBfbnVtZXJhdG9yW10sIGludCBwX2Rlbm9taW5hdG9yW10sIGludCBmYWN0b3JzX2EwW10sIGludCBmYWN0b3JzX2FuW10sIGludCBudW1fZmFjdG9yc19hMCwgaW50IG51bV9mYWN0b3JzX2FuKQp7CglpbnQgaSwgaiwgZ2NkLCBlbGVtZW50ID0gMDsKCQoJZm9yKGkgPSAwOyBpIDwgbnVtX2ZhY3RvcnNfYTA7aSsrKQoJewoJCWZvcihqID0gMDsgaiA8IG51bV9mYWN0b3JzX2FuO2orKykKCQl7CgkJCWdjZCA9IGdldF9nY2QoZmFjdG9yc19hMFtpXSwgZmFjdG9yc19hbltqXSk7CgkJCWlmKGdjZCA9PSAxKQoJCQl7CgkJCQlwX251bWVyYXRvcltlbGVtZW50XSA9IGZhY3RvcnNfYTBbaV07CgkJCQlwX2Rlbm9taW5hdG9yW2VsZW1lbnRdID0gZmFjdG9yc19hbltqXTsKCQkJCWVsZW1lbnQrKzsKCQkJfQoJCX0KCX0KfQoKaW50IGdldF9nY2QoaW50IG51bTEsIGludCBudW0yKQp7Cgl3aGlsZShudW0xIT1udW0yKQoJewoJCWlmKG51bTE+bnVtMikKCQkJbnVtMS09bnVtMjsKCQllbHNlCgkJCW51bTItPW51bTE7Cgl9CglyZXR1cm4gbnVtMTsKfQoKaW50ICBnZXRfcmF0aW9uYWxfcm9vdHNfc2l6ZShpbnQgcG9seW5vbWlhbF9kZWdyZWUsIGRvdWJsZSBwb2x5bm9taWFsX2NvZWZmaWNpZW50c1tdLCBkb3VibGUgcG9zc2libGVfcm9vdHNbXSwgaW50IG51bV9wb3NzaWJsZV9yb290cykKewoJaW50IGksIGosIG51bV9yYXRpb25hbF9yb290cyA9IDA7Cglkb3VibGUgcXVvdGllbnRfY29lZmZpY2llbnRzW3BvbHlub21pYWxfZGVncmVlXTsKCQoJcXVvdGllbnRfY29lZmZpY2llbnRzWzBdID0gcG9seW5vbWlhbF9jb2VmZmljaWVudHNbcG9seW5vbWlhbF9kZWdyZWVdOwoJZm9yKGkgPSAwOyBpIDwgbnVtX3Bvc3NpYmxlX3Jvb3RzOyBpKyspCgl7CgkJZm9yKGo9MTtqPD1wb2x5bm9taWFsX2RlZ3JlZTtqKyspCgkJewoJCQlxdW90aWVudF9jb2VmZmljaWVudHNbal0gPSAocXVvdGllbnRfY29lZmZpY2llbnRzW2otMV0qcG9zc2libGVfcm9vdHNbaV0pK3BvbHlub21pYWxfY29lZmZpY2llbnRzW3BvbHlub21pYWxfZGVncmVlLWpdOwoJCQlpZihxdW90aWVudF9jb2VmZmljaWVudHNbMl0gPT0gMCAmJiBqID09IDIpCgkJCXsKCQkJCW51bV9yYXRpb25hbF9yb290cysrOwoJCQl9CgkJfQoJfQoJcmV0dXJuIG51bV9yYXRpb25hbF9yb290czsKfQoKdm9pZCBnZXRfcmF0aW9uYWxfcm9vdHMoaW50IHBvbHlub21pYWxfZGVncmVlLCBkb3VibGUgcG9seW5vbWlhbF9jb2VmZmljaWVudHNbXSwgZG91YmxlIHBvc3NpYmxlX3Jvb3RzW10sIGludCBudW1fcG9zc2libGVfcm9vdHMsIGRvdWJsZSByYXRpb25hbF9yb290c1tdKQp7CglpbnQgaSwgaiwgZWxlbWVudCA9IDA7Cglkb3VibGUgcXVvdGllbnRfY29lZmZpY2llbnRzW3BvbHlub21pYWxfZGVncmVlXTsKCQoJcXVvdGllbnRfY29lZmZpY2llbnRzWzBdID0gcG9seW5vbWlhbF9jb2VmZmljaWVudHNbcG9seW5vbWlhbF9kZWdyZWVdOwoJZm9yKGkgPSAwOyBpIDwgbnVtX3Bvc3NpYmxlX3Jvb3RzOyBpKyspCgl7CgkJZm9yKGo9MTtqPD1wb2x5bm9taWFsX2RlZ3JlZTtqKyspCgkJewoJCQlxdW90aWVudF9jb2VmZmljaWVudHNbal0gPSAocXVvdGllbnRfY29lZmZpY2llbnRzW2otMV0qcG9zc2libGVfcm9vdHNbaV0pK3BvbHlub21pYWxfY29lZmZpY2llbnRzW3BvbHlub21pYWxfZGVncmVlLWpdOwoJCQlwcmludGYoIlJlc3VsdCAlZCA9ICVsZlx0IiwgaiwgcXVvdGllbnRfY29lZmZpY2llbnRzW2pdKTsKCQkJaWYocXVvdGllbnRfY29lZmZpY2llbnRzWzJdID09ICswIHx8IHF1b3RpZW50X2NvZWZmaWNpZW50c1syXSA9PSAtMCkKCQkJewoJCQkJcmF0aW9uYWxfcm9vdHNbZWxlbWVudF0gPSBwb3NzaWJsZV9yb290c1tpXTsKCQkJCXByaW50ZigiXG5Sb290ICVsZiBhdCBpID0gJWQsIGogPSAlZFxuIiwgcmF0aW9uYWxfcm9vdHNbZWxlbWVudF0sIGksIGopOwoJCQkJZWxlbWVudCsrOwoJCQl9CgkJfQoJCXByaW50ZigiXG4iKTsKCX0KfQ==