PGR21.com
이전 질문 게시판은 새 글 쓰기를 막았습니다. [질문 게시판]을 이용바랍니다.
Date 2011/10/25 23:51:28
Name 학부대수학의반
Subject C언어 초고수 분들 제발 좀 굽신굽신......
N과 s를 입력했을때,(4<N<60, 0<s<17 의 조건을 줍니다.)

64비트 (unsigned)정수에서 자릿수가 1인 것이 N개 있는 수를 총 2^s개 (서로 다르게)만들어 내는 코드를 짜고 싶은데,

(이왕이면 규칙성 있게요.)

잘 모르겠어요ㅠㅠ;


이해가 쉽게 16비트로 간략화 시켜서 말씀드리면

예를 들어 N=9, s=4 (따라서, 총 16개) 을 입력하면

arr[0]=0001 1111 1111 1111

arr[1]=0010 1111 1111 1111

arr[2]=0011 0111 1111 1111

arr[3]=0011 1011 1111 1111

arr[4]=0011 1101 1111 1111

arr[5]=0011 1110 1111 1111

arr[6]=0011 1111 0111 1111

arr[7]=0011 1111 1011 1111

arr[8]=0011 1111 1101 1111

arr[9]=0011 1111 1110 1111

arr[10]=0011 1111 1111 0111

arr[11]=0011 1111 1111 1011

arr[12]=0011 1111 1111 1101

arr[13]=0011 1111 1111 1110

arr[14]=0100 1111 1111 1111

arr[15]=0101 0111 1111 1111


이런 식으로 나올 수 있도록 하는 것인데요.



그 다음에 위에서 생성된 2^s개의 64비트 (unsigned)정수의 자릿수가 1인 것이 N개 있는 수 중에서 하나를 뽑고,

다른 64비트 (unsigned)정수를 아무거나 하나를 가져왔을때,

위에서 뽑은 수에서 1이있는 자리랑 동일한 자리만 남겨서 붙인다음 새로 64비트 (unsigned)정수를 만들고 싶은데요.



예를 들었던 16비트 버젼으로 쉽게 설명해드리면,

arr[15]=0101 0111 1111 1111 를 뽑고, 다른 16비트 정수 1111 1110 0000 0000를 가져왔다면,

0[1]0[1] 0[111 1111 1111]
1[1]1[1] 1[110 0000 0000]  를 비교해보고 위쪽에 1이 있는 자리수를 남겨서

000[1] [1][110 0000 0000]=0001 1110 0000 0000 라는 정수를 만드는 프로그램입니다.



C배운지 이제 2달 남짓 되었는데 도저히 이런 걸 어떻게 만들어야 할지 모르겠네요 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ;

제발 좀 도와주세요................;


p.s 혹시나 해서 말씀드리는데 숙제 같은건 아니고요. 논문을 쓰려고 이론을 정립해놨는데, 실험을 해봐야 하는데 이런 코드가 필요하거든요ㅠ;

통합규정 1.3 이용안내 인용

"Pgr은 '명문화된 삭제규정'이 반드시 필요하지 않은 분을 환영합니다.
법 없이도 사는 사람, 남에게 상처를 주지 않으면서 같이 이야기 나눌 수 있는 분이면 좋겠습니다."
프즈히
11/10/26 01:47
수정 아이콘
#include <stdio.h>
#include <math.h>


void print_binary(long int x)

if (x > 0)
{
print_binary(x/2);
printf("%d",x%2);


}

int main()

long int i, j, k;
int shift;
int n = 9; // n
int s = 4; // s
int count = 0;
long int start = pow(2,n) -1;
long int end = pow(2,n+1) - 2;

s = pow(2,s);


for( k = 1 ; count < s ;)
{
j = 1;

for( i = end ; i >= start ; )
{
if (count < s)
{
print_binary(i*k);
printf("\n");
i = i-j;
j = j*2;
count++;

}

k = k*2;
}

return 0;
}
프즈히
11/10/26 02:04
수정 아이콘
나중에 더하는 부분은 잘 이해가 안되서 자릿수가 1인 것이 N개 있는 수를 총 2^s개 출력하는 부분만 해보았습니다.
출력 결과에서 앞에 자릿수에 0이 생략되어 있는 형태로 출력됩니다. (졸려서 더 수정을 못했습니다.)
예를들어 1111010 이라고 출력된다면 실제로는
0000 00... ...011 11010
이라는 의미입니다.

위쪽에 1이 있는 자리수를 남기는 연산을 하신다고 하셨는데(제가 잘 이해를 못해서 구현을 못했습니다.)
괜히 저 10진수를 2진수로 바꿔서 계산하려고 노력하시기 보다는 비트연산을 공부하셔서 잘 적용하시면 쉽게 끝날 것 같습니다. (마스크를 만든다든가..)

논문 작성중이시라니 저 알고리즘의 아이디어에 조금 더 설명을 덧붙이자면
1이 n개 있는 2진수의 집합은
십진수 2^(n+1)-1 에서 2^(n)-1 까지 2의 x제곱(x는 0부터 ~ )만큼 뺀 수의 집합이라는 성질을 이용해 본 것입니다.
(그냥 눈으로 끄적끄적 하다가 발견한거라 이부분에 수학적 이론 배경이 있는지는 모르겠습니다.)
뭔가 말만 어렵게 됬는데 가령 n이 10인 집합은 (k = 1)

(2^(10+1)-1 - 2^0) * k = 2046 = 0000 00... ...0111 1111 1110
(2^(10+1)-1 - 2^1) * k = 2045 = 0000 00... ...0111 1111 1101
(2^(10+1)-1 - 2^2) * k = 2043 = 0000 00... ...0111 1111 1011
(2^(10+1)-1 - 2^3) * k = 2039 = 0000 00... ...0111 1111 0111
...
(2^(10+1)-1 - 2^10) * k = 1023 = 0000 00... ...0011 1111 1111

아시겠죠 -_-;;?
만일 s가 커서 자릿수 이동이 필요하다면 k를 2배씩 증가해 주시면 한칸씩 왼쪽으로 미는 효과가 나서 해결됩니다.
가령 k가 2라면
0000 00... ...1111 1111 1100
...

k가 4라면
0000 00... ...0001 1111 1111 1000
...



셤공부 하는데 공부가 안되서 잠깐 만져본거라 좀 지저분 합니다.
프로그래밍 보다는 수학쪽 잘 아시는 분께 여쭤보시면 좀 더 심플하고 스마트한 알고리즘으로 다듬어져 나올 것 같습니다.
이런저런 논리상 오류가 있을지도 모르니 충분히 검증하신 후 다듬어서 사용하시기 바랍니다.

- 지나가던 컴퓨터학부생 -
11/10/26 13:52
수정 아이콘
이걸 내가 왜 하나 한탄하면서 했습니다.. 생성된 수와 연산을 할 수를 랜덤 생성하시는지 주어지는지 모르겠지만, 그 부분만 보고 고치시면 되요.

#include <stdio.h>
#include <stdlib.h> // malloc
#include <assert.h> // assert
#include <string.h> // memset

#define NUM_BIT_WIDTH 64
#define ERR_CODE 1
/**
* @brief if success, return non-zero
*
*/
int
generate_numbers( const unsigned long int* out_array, ///< result. alloc!
unsigned int N, ///< N
unsigned int s ///< s
);

void
print_in_bin( const unsigned long int src, const unsigned int bit_vector_width );


unsigned long int
do_operation( const unsigned long int first_num, ///< having N 1s
const unsigned long int second_num, ///< randomly selected?
const unsigned int bit_vector_width
);

int main( int argc, char* argv[], char* envp[] )

unsigned int j = 0;
unsigned int N = 0, s = 0;
scanf( "%d %d", &N, &s );

unsigned int cnt = 1 << s; // 2^s, it's safe since s^2 is in unsigned integer boundary
unsigned long int* result = ( unsigned long int* ) malloc( sizeof( unsigned long int ) * cnt );
unsigned long int* ramdom_selected_numbers = ( unsigned long int* ) malloc( sizeof( unsigned long int ) * cnt );
// for scripting, if generate_numbers fails,
// it lets the shell knows this program failed
if ( generate_numbers( result, N, s ) == 0 )
{
free( result );
free( ramdom_selected_numbers );
return ERR_CODE; // error, now shell script will be able to detect this error

else
;

unsigned int print_idx = 0;
for ( ; print_idx < cnt ; print_idx++ )

printf( "A[ %2d ] = 0x%lx, ", print_idx, result[ print_idx ] );
print_in_bin( result[ print_idx ], NUM_BIT_WIDTH );
printf( "\n" );


// do operation on all result's elements
for ( j = 0 ; j < cnt ; j++ )

unsigned long int computed_value = 0;
unsigned int upper = rand();
unsigned int lower = rand();
unsigned int random_num = 0xFFFFFFFFL & lower;
random_num += ( 0xFFFFFFFF00000000L ) & upper;
ramdom_selected_numbers[ j ] = random_num;
computed_value = do_operation( result[ j ], random_num, NUM_BIT_WIDTH );

// computed value is the result of this iteration
printf( "At #%d cycle : \n", j );
print_in_bin( result[j], NUM_BIT_WIDTH );
printf("\n");
print_in_bin( random_num, NUM_BIT_WIDTH );
printf(" is \n" );
print_in_bin( computed_value, NUM_BIT_WIDTH );
printf( "\n\n" );



free( result );
free( ramdom_selected_numbers );
return 0; // normal termination

}

unsigned long int
do_operation( const unsigned long int first_num, ///< having N 1s
const unsigned long int second_num, ///< randomly selected?
const unsigned int bit_vector_width
)

// scan 1st num from MSB to LSB, the idx is i
// if ( first_num[ i ] == 1 ), leave second_num[i]
unsigned long int computed_result = 0;
unsigned int i = 0;
unsigned long int mask = 0x1L << ( bit_vector_width - 1 ); // if bit vector is 5 bits, 0b10000 should be mask to pick the MSB up

unsigned int cnt = 0;

// mask will be shifted right to see the next largest bit at every iteration
assert( bit_vector_width <= 64 );
for ( i = 0 ; i < bit_vector_width ; i++, mask >>= 1 )
{
if ( first_num & mask )
{
computed_result <<= 1; // push left,
if ( ( second_num & mask ) != 0 ) // set LSB with second_num
computed_result += 1;
cnt++;

else
;
}
return computed_result;
}

unsigned long int
to_number( unsigned int* bit_vector, unsigned int bit_vector_size )

unsigned int i = 0;
unsigned int result = 0;
unsigned int value_to_add = 1;
assert( bit_vector );
assert( bit_vector_size <= 64 );
for ( i = 0 ; i < bit_vector_size; i++, value_to_add <<= 1 )
{
if ( bit_vector[ i ] == 1 ) // bit set, then add value_to_add
result += value_to_add;
else
; // skip

return result;
}

int
generate_numbers( const unsigned long int* out_array, ///< result. alloc!
unsigned int N, ///< N
unsigned int s ///< s
)

unsigned int i = 0, j = 0; // loop idx, don't care
unsigned long int* data_write_pos = (unsigned long int*) out_array; // where to write new number

// check if 64Cn >= 2^s,
// I can do that but it takes time, I don't have time.
// Note that 64!, n!, 64-n! are much bigger than long long int boundary
// A simple approach is to use prime number counter

// choose N numbers in increasing order

// algorithm is as follows
// Assume that we just found a number x, for example, 0x110010, where N = 6
// Then, bit_vector_of_max = [0, 1, 0, 0, 1, 1 ]; from LSB to MSB
// We will find the next bigger one!
// It's easy. from leftmost, e.g., LSB, find '10' and replace it with '01'
// Then, make bit_vector_of_max a number and store the number in the result array

unsigned int cnt = 1 << s; // 2^s, it's safe since s^2 is in unsigned integer boundary
unsigned int* bit_vector_of_max = ( unsigned int* ) malloc( sizeof( unsigned int ) * NUM_BIT_WIDTH );
memset( bit_vector_of_max, 0, sizeof( unsigned int ) * N ); // initialize bit_vector with 0s

// cnt >= 1

// find the minimum number that meets the condition
// e.g. set only N lowest bits as 1
for ( i = 0 ; i < N; i++ )// make bit vector for 1st, minimum number
bit_vector_of_max[i] = 1;
*data_write_pos = to_number( bit_vector_of_max, NUM_BIT_WIDTH ); // write first number
cnt--;

// iterative step, which is explained at the beginning of the function
while( cnt > 0 )
{
unsigned char is_update = 0; // successfully got a next larger number?

// advance bit vector
// find 1, 0
for ( j = 0 ; j < NUM_BIT_WIDTH - 1 ; j++ )
{
if ( bit_vector_of_max[ j ] == 1 &&
bit_vector_of_max[ j + 1 ] == 0 )
// bingo!
{
//swap
bit_vector_of_max[ j ] = 0;
bit_vector_of_max[ j + 1 ] = 1;

// write data
data_write_pos++; *data_write_pos = to_number( bit_vector_of_max, NUM_BIT_WIDTH );

// mark as updated
is_update = 1;
break; // quit the for loop

else
; // keep going
}

if ( ! is_update )
return 0; // something wrong, I have to find more numbers but failed
else
--cnt;
}
return 1; // success
}

void print_in_bin( const unsigned long int src, const unsigned int bit_vector_width )

unsigned int i = 0;
unsigned long int mask = 0x1L << ( bit_vector_width - 1 ); // if bit vector is 5 bits, 0b10000 should be mask to pick the MSB up
// mask will be shifted right to see the next largest bit at every iteration
assert( bit_vector_width <= 64 );
printf( "0x" );
for ( i = 0 ; i < bit_vector_width; i++ )
{
if ( mask & src ) // 1
printf( "1" );
else
printf( "0" );
mask >>= 1;

}
11/10/26 13:57
수정 아이콘
코드는 64비트 리눅스 머신에서 테스트 했습니다. 아마 윈도우즈라서 다를만한 부분은 0x1L 이나 unsigned long int 부분일 텐데, 전자는 64비트 짜리 부호가 없는 상수여야 되고, 후자는 64비트 부호가 없는 정수형 변수 타입이어야 됩니다.
목록 삭게로! 맨위로
번호 제목 이름 날짜 조회
117691 아스날 경기 볼 수 있는 곳 있나요? [5] 신장9등급2169 11/10/26 2169
117690 bgm 질문. [2] zephyrus1942 11/10/26 1942
117689 아웃룩 2007 맞춤법 검사 질문입니다.. [3] WestSide1934 11/10/26 1934
117688 트리플H 물 뿜는거 어떨게 하나요?? [13] 밴더4080 11/10/26 4080
117686 학교 도서실에 맘에 든느 여학우 [9] 고마유2650 11/10/26 2650
117685 드라고나 해보신분 계신가요? [1] 불타는부채꼴1678 11/10/26 1678
117684 소셜커머스에서 파는 순금질문입니다. [1] worcs1617 11/10/26 1617
117682 제 넷북 정도면 얼마에 팔수 있을까요? [3] 아스날1698 11/10/26 1698
117681 회사 다니시는 분들중 투표하시는 분들 내일 몇시에 출근 할 예정인가요? [5] Eva0101804 11/10/26 1804
117680 남자 향수 초보 향수 추천 부탁드립니다. [2] SiveRiuS1821 11/10/26 1821
117679 LoL 질문 드립니다. [10] J-ark2191 11/10/26 2191
117678 19금)남자의 성기에 관한 질문입니다. [20] 투에이치9795 11/10/25 9795
117677 여성가족부의 행태에 대해 알고 싶습니다. [2] 치킨마요는 혁신이다1611 11/10/25 1611
117676 사진 올릴때 태그를 써야되나요? [8] 스타1587 11/10/25 1587
117675 C언어 초고수 분들 제발 좀 굽신굽신...... [4] 학부대수학의반1913 11/10/25 1913
117674 전자 세금계산서 질문입니다. [5] 독수리2118 11/10/25 2118
117673 술먹고 차량을 파손시켰는데... 질문입니다. [18] 풍운4419 11/10/25 4419
117672 내일 선거에서 한나라당이 패배할경우 [11] 뜨거운눈물2188 11/10/25 2188
117671 nh농협 체크카드 계자이체 [3] NaS.KiJuK1710 11/10/25 1710
117670 운동전에 콜라 마시는것 어떤가요? [7] 릴리러쉬.4269 11/10/25 4269
117669 대통령 지지율 관련 질문입니다. 호삼미도반2123 11/10/25 2123
117668 유클리드 호제법 질문입니다. [1] 루시리스1661 11/10/25 1661
117667 단체복으로 윈드브레이커도 괜찮나요? DEICIDE1675 11/10/25 1675
목록 이전 다음
댓글

+ : 최근 6시간내에 달린 댓글
+ : 최근 12시간내에 달린 댓글
맨 위로