Olej писал(а): ↑29.01.2016 13:47№1 : Известно, что правильная рациональная дробь N / M ( N < M ) в десятичной записи может давать либо конечную запись ( 2 / 5 = 0.4 ), либо периодическую запись ( 1 / 3 = 0.(3) ). Рациональная дробь не может производить иррациональное значение (с непериодической десятичной записью, как, например, SQRT( 2 ) ). Создайте программу преобразования рациональной дроби в позиционную запись. Примите во внимание, что период может начинаться не с 1-й цифры после запятой: 1 / 12 = 0.08(3). Чтобы задача не казалась слишком лёгкой, сделайте её для произвольной системы счисления, основание которой (не только 10) вводится как отдельный параметр, например в 2-чной системе 2 / 3 = 0.(10) = 1 * ½ + 0 * ¼ + ...
Код: Выделить всё
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
inline char simb( unsigned val ) {
return val < 10 ? '0' + val : 'A' + val - 10;
}
unsigned input( char *msg ) {
int i;
unsigned ret = 0;
printf( "%s", msg );
fflush( stdout );
if( ( i = scanf( "%u", &ret ) ) <= 0 || ret <= 0 ) {
printf( "ошибка ввода\n" );
exit( 1 );
}
return ret;
}
void show( int n, unsigned ost, unsigned arr[] ) { // только для отладки:
unsigned i;
printf( "%3u -> {[%d]: ", ost, n );
for( i = 0; i < n && arr[ i ] >= 0; i++ )
printf( "%u ", arr[ i ] );
printf( "}\n" );
};
int main( int argc, char **argv ) {
int i, j, debug = ( argc > 1 &&
( 0 == strcmp( argv[ 1 ], "-v" ) ||
0 == strcmp( argv[ 1 ], "debug" ) ) );
while( 1 ) {
unsigned metr, ch, zn;
metr = input( "система счисления: " );
ch = input( "числитель: " );
zn = input( "знаменатель: " );
if( ch >= zn ) {
printf( "должнв быть правльная дробь!\n" );
continue;
}
char *sval = (char*)calloc( zn + 1, sizeof( char ) );
unsigned *list = (unsigned*)calloc( zn, sizeof( unsigned ) );
for( i = 0; i < zn; i++ ) list[ i ] = -1;
unsigned ost = ch; // остаток от деления
for( i = 0; ; i++, ost *= metr ) {
if( i > 0 ) sval[ i - 1 ] = simb( ost / zn );
ost %= zn;
if( debug ) show( i, ost, list );
if( 0 == ost ) break;
for( j = 0; j < i; j++ )
if( ost == list[ j ] ) break; // найден совпадающий остаток
if( i == 0 || j == i )
list[ i ] = ost;
else {
ost = i - j;
break;
}
}
sval[ i ] = '\0';
free( list );
char *sres = (char*)calloc( strlen( sval ) + 4, sizeof( char ) );
strcpy( sres, "0." );
i = strlen( sval ) - ost;
strncpy( sres + strlen( sres ), sval, i );
if( ost > 0 ) {
strcat( sres, "(" );
strcat( sres, sval + i );
strcat( sres, ")" );
}
printf( "длина периода %u : %u / %u = %s\n", ost, ch, zn, sres );
free( sval );
free( sres );
}
return 0;
}
Если с отладкой, чтобы видеть как это происходит:
Код: Выделить всё
$ ./period1 debug
система счисления: 10
числитель: 11
знаменатель: 13
11 -> {[0]: }
6 -> {[1]: 11 }
8 -> {[2]: 11 6 }
2 -> {[3]: 11 6 8 }
7 -> {[4]: 11 6 8 2 }
5 -> {[5]: 11 6 8 2 7 }
11 -> {[6]: 11 6 8 2 7 5 }
длина периода 6 : 11 / 13 = 0.(846153)
Если без (в конечном виде) + несколко результатовв качестве тестовых данных, если кому-то будет интересно улучшить и сравнить код:
Код: Выделить всё
$ ./period1
система счисления: 2
числитель: 17
знаменатель: 47
длина периода 23 : 17 / 47 = 0.(01011100100110001000001)
система счисления: 8
числитель: 53
знаменатель: 59
длина периода 58 : 53 / 59 = 0.(7137352234150105330745756511606404255436276724470320212661)
система счисления: 10
числитель: 283
знаменатель: 293
длина периода 146 : 283 / 293 = 0.(96587030716723549488054607508532423208191126279863481228668941979522184300341296928327645051194539249146757679180887372013651877133105802047781569)