FizzBuzz по-македонски

6b21236908004a6cb0cd33419eba2565

Long story short

Сеньоры начинают и проигрывают

@qrdl — ничего личного.

Тут как на олимпийских играх — быстрее, короче, изящней.

В продолжение увлекательной дискуссии

https://habr.com/ru/post/540136/

https://habr.com/ru/post/682080/

https://habr.com/ru/post/682332/

Сеньоры в 4 потока

time ./multithreaded2 > /dev/null

real 0m1,173s user 0m4,158s sys 0m0,140s

Этот пенсионерский код в те же 4 потока дает

time ./my_5_thread > /dev/null

real 0m0,824s user 0m3,162s sys 0m0,016s

на машине

model name: Intel® Core i5–3317U CPU @ 1.70GHz (какая есть))

/*
 ============================================================================
 Name        : my_5_thread.c
 Author      : Peter Che 7210208@gmail.com
 Version     :
 Copyright   : Учитесь
 Description : FizzBuzz in C
 ============================================================================
 */

#include 
#include 
#include 
#include 
#include 
#include 

#define CHUNK_SIZE  238 // 16*10 + 58

pthread_spinlock_t spin_c[3];
pthread_spinlock_t spin_p[3];

struct bufs {
	uint64_t	number;
	size_t		count;
	size_t		len;
	size_t		size;
	char*		start;
	char*		buf;
};
struct bufs buf_g[3];

uint64_t n11[8] = { 0 };
uint64_t test[8] = { 0 };
uint64_t n10[8] = { 0 };
uint64_t n010[8] = { 0 };
uint64_t n1[8] = { 0 };
uint64_t add_3 = 0x0300000000000000;


#define DIGIT_1 do { *(uint64_t*)cur = 0x0a31000000000000; cur -= 2; *((uint64_t*)cur) = t_num; cur -= t_len; } while (0)
#define DIGIT_2 do { *(uint64_t*)cur = 0x0a32000000000000; cur -= 2; *((uint64_t*)cur) = t_num; cur -= t_len; } while (0)
#define DIGIT_3 do { *(uint64_t*)cur = 0x0a33000000000000; cur -= 2; *((uint64_t*)cur) = t_num; cur -= t_len; } while (0)
#define DIGIT_4 do { *(uint64_t*)cur = 0x0a34000000000000; cur -= 2; *((uint64_t*)cur) = t_num; cur -= t_len; } while (0)
#define DIGIT_6 do { *(uint64_t*)cur = 0x0a36000000000000; cur -= 2; *((uint64_t*)cur) = t_num; cur -= t_len; } while (0)
#define DIGIT_7 do { *(uint64_t*)cur = 0x0a37000000000000; cur -= 2; *((uint64_t*)cur) = t_num; cur -= t_len; } while (0)
#define DIGIT_8 do { *(uint64_t*)cur = 0x0a38000000000000; cur -= 2; *((uint64_t*)cur) = t_num; cur -= t_len; } while (0)
#define DIGIT_9 do { *(uint64_t*)cur = 0x0a39000000000000; cur -= 2; *((uint64_t*)cur) = t_num; cur -= t_len; } while (0)

#define FIZZ do { *((uint64_t*) cur) = 0x0a7a7a6946000000; cur -= 5; } while (0)
#define FIZZBUZZ do { *((uint64_t*)cur) = 0x0a0a0a0a0a0a0a0a; cur--; *((uint64_t*)cur) = 0x7a7a75427a7a6946; cur -= 8; } while (0)
#define FIZZ_BUZZ do { *((uint64_t*)cur) = 0x0a7a000000000000;  cur -= 2; *((uint64_t*)cur) = 0x7a75420a7a7a6946; cur -= 8; } while (0)
#define BUZZ_FIZZ do { *((uint64_t*)cur) = 0x0a7a000000000000;  cur -= 2; *((uint64_t*)cur) = 0x7a69460a7a7a7542; cur -= 8; } while (0)


uint64_t num_count = 73*101;
uint64_t num_len = 137*11;
// = 11×73×101×137

uint64_t buf_len;

void* my_sub_0(void* arg) {
	int thread_num;
	int i;
	char* buf;
	char* cur = NULL;
	thread_num = *(int*)arg;
	buf = buf_g[thread_num].buf;

	uint64_t num[3]; // = { 0x3030303030303030, 0x3030303030303030, 0x3030303030303030 };
	int len[3]; 	 // = { 8, 8, 8 };

	uint64_t t_num;
	int t_len;

	int k;
	uint64_t t_number;
	uint64_t number;

	int j;
	int jj = 1;
	while (1) {
		pthread_spin_lock(&spin_c[thread_num]);
		buf_g[thread_num].number = (jj + thread_num) * (buf_g[thread_num].count * 3);
		number = buf_g[thread_num].number;
		if (number > 99999999)
			break;
		jj += 3;
		i = 2;
		while (i >= 0) {
			k = 0;
			t_number = number + i - 2;
			cur = (char*)&num[i] + 8;
			do {
				*--cur = t_number % 10 + '0';
				t_number /= 10;
				k++;
			} while (t_number != 0);
			len[i] = k;
			i--;
		}

		cur = buf + buf_g[thread_num].size - 8;
		for (j = 0; j < buf_g[thread_num].count; j++) {
			t_num = num[2];
			t_len = len[2];
			FIZZ_BUZZ;
			DIGIT_8;
			DIGIT_7;
			BUZZ_FIZZ;
			DIGIT_4;
			FIZZ;
			DIGIT_2;
			DIGIT_1;

			t_num = num[1];
			t_len = len[1];
			FIZZBUZZ;
			DIGIT_9;
			DIGIT_8;
			FIZZ;
			DIGIT_6;
			FIZZ_BUZZ;
			DIGIT_3;
			DIGIT_2;

			t_num = num[0];
			t_len = len[0];
			BUZZ_FIZZ;
			DIGIT_9;
			FIZZ;
			DIGIT_7;
			DIGIT_6;
			FIZZBUZZ;
			DIGIT_4;
			DIGIT_3;
			FIZZ;
			DIGIT_1;

			for (i = 2; i >= 0; i--) {
				k = 0;
				num[i] -= add_3;
				do {
					if ((num[i] & test[k]) >= n010[k])
						break;
					num[i] += n11[k];
					k++;
					if ((k == (len[i] - 1))
						&& ((num[i] & test[k]) == n010[k])) {
						len[i]--;
						break;
					}
				} while (1);
			}
		}
		buf_g[thread_num].len = buf + buf_g[thread_num].size - cur - 8;
		buf_g[thread_num].start = cur + 8;
		pthread_spin_unlock(&spin_p[thread_num]);
		number += 3 * (buf_g[thread_num].count * 3);
	}
	return 0;
}

void* send_out(void* arg) {
	const char *buf_0 = "1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n";
	fwrite(buf_0, 35, 1, stdout);
	do {
		pthread_spin_lock(&spin_p[0]);
		fwrite(buf_g[0].start, buf_g[0].len, 1, stdout);
		pthread_spin_unlock(&spin_c[0]);

		pthread_spin_lock(&spin_p[1]);
		fwrite(buf_g[1].start, buf_g[1].len, 1, stdout);
		pthread_spin_unlock(&spin_c[1]);

		pthread_spin_lock(&spin_p[2]);
		fwrite(buf_g[2].start, buf_g[2].len, 1, stdout);
		pthread_spin_unlock(&spin_c[2]);
		if (buf_g[2].number >= 99999999)
			break;
	} while (1);
	pthread_exit(NULL);
	return 0;
}

int main() {
	pthread_t threads[4];

	buf_g[0].count = num_len;
	buf_g[1].count = num_len;
	buf_g[2].count = num_len;
	buf_g[0].size = CHUNK_SIZE * num_len;
	buf_g[1].size = CHUNK_SIZE * num_len;
	buf_g[2].size = CHUNK_SIZE * num_len;
	buf_g[0].len = 0;
	buf_g[1].len = 0;
	buf_g[2].len = 0;
	buf_g[0].number = 0;
	buf_g[1].number = 0;
	buf_g[2].number = 0;

	buf_g[0].buf = (char*)malloc(buf_g[0].size + 1);
	buf_g[1].buf = (char*)malloc(buf_g[1].size + 1);
	buf_g[2].buf = (char*)malloc(buf_g[2].size + 1);

	n10[0] = 0x0a00000000000000;
	n10[1] = 0x000a000000000000;
	n10[2] = 0x00000a0000000000;
	n10[3] = 0x0000000a00000000;
	n10[4] = 0x000000000a000000;
	n10[5] = 0x00000000000a0000;
	n10[6] = 0x0000000000000a00;
	n10[7] = 0x000000000000000a;

	n010[0] = 0x3000000000000000;
	n010[1] = 0x0030000000000000;
	n010[2] = 0x0000300000000000;
	n010[3] = 0x0000003000000000;
	n010[4] = 0x0000000030000000;
	n010[5] = 0x0000000000300000;
	n010[6] = 0x0000000000003000;
	n010[7] = 0x0000000000000030;

	n1[0] = 0x0001000000000000;
	n1[1] = 0x0000010000000000;
	n1[2] = 0x0000000100000000;
	n1[3] = 0x0000000001000000;
	n1[4] = 0x0000000000010000;
	n1[5] = 0x0000000000000100;
	n1[6] = 0x0000000000000001;
	n1[7] = 0x0000000000000000;

	test[0] = 0xff00000000000000;
	test[1] = 0x00ff000000000000;
	test[2] = 0x0000ff0000000000;
	test[3] = 0x000000ff00000000;
	test[4] = 0x00000000ff000000;
	test[5] = 0x0000000000ff0000;
	test[6] = 0x000000000000ff00;
	test[7] = 0x00000000000000ff;

	int k;
	for (k = 0; k < 8; k++) {
		n11[k] = n10[k] - n1[k];
	}

	pthread_spin_init(&spin_c[0], 0);
	pthread_spin_init(&spin_p[0], 0);
	pthread_spin_init(&spin_c[1], 0);
	pthread_spin_init(&spin_p[1], 0);
	pthread_spin_init(&spin_p[2], 0);
	pthread_spin_init(&spin_c[2], 0);

	pthread_spin_lock(&spin_p[0]);
	pthread_spin_lock(&spin_p[1]);
	pthread_spin_lock(&spin_p[2]);

	int id0 = 0;
	int id1 = 1;
	int id2 = 2;
	pthread_create(&threads[0], NULL, my_sub_0, &id0);
	pthread_create(&threads[1], NULL, my_sub_0, &id1);
	pthread_create(&threads[2], NULL, my_sub_0, &id2);
	pthread_create(&threads[3], NULL, send_out, NULL);

	pthread_join(threads[0], NULL);
	pthread_join(threads[1], NULL);
	pthread_join(threads[2], NULL);
	pthread_join(threads[3], NULL);

	pthread_spin_destroy(&spin_c[0]);
	pthread_spin_destroy(&spin_c[1]);
	pthread_spin_destroy(&spin_c[2]);
	pthread_spin_destroy(&spin_p[0]);
	pthread_spin_destroy(&spin_p[1]);
	pthread_spin_destroy(&spin_p[2]);

	return 0;
}

Сеньоры привыкают начинать с центра поля))

Жду с нетерпением ответ. Буду только рад, если он будет быстрее, короче и изящней.

P.S. Всем ценителям и критикам моего пенсионерского изящного говнокода — велком

© Habrahabr.ru