powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Решение одной задачи
25 сообщений из 76, страница 3 из 4
Решение одной задачи
    #38917569
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
int isPrime(int x)
{
	if (x == 1)    return 0;
	for (int i = 2; i <= (int)sqrt((float)x); ++i){
		if (x%i == 0)    return 0;
	}
	return 1;
}



Это неоптимально. При проверке на Prime можно сразу скипать чётные числа. Шаг делать равным 2.
А двойку проверить отдельно вне цикла.

Код: plaintext
1.
	for (int i = 3; i <= (int)sqrt((float)x); i+=2){



Это нужно выкинуть нафиг.
Код: plaintext
1.
sqrt((float)x)



Есть инкрементальный целочисленный расчёт квадратного корня. Есть просто целочисленный квадратный
корень.

Ищите в форуме мои посты 2-х годичной давности. Там генератор простых чисел обсуждался.

+
Если уже имеется вектор расчитанных простых то их можно использовать в качестве делителей.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38917631
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Без таблицы никак, иначе считать каждый раз. Тут хорошо расписана оптимизация генераторов. http://habrahabr.ru/post/122538/
Переписал оттуда генератор на С
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
#include <stdio.h>
#include <vector>

std::vector<int> primaries;

void fill_primaries(int max)
{
	primaries.clear();
	primaries.push_back(2);
	for(int i = 3; i <= max; i += 2) {
		int* k = &primaries[0];
		for(int j = primaries.size(); j > 0 && i % *k != 0; j--,k++) {
			if(*k * *k > i) {
				primaries.push_back(i);
				break;
			}
		}
	}
}

void  main(){
	fill_primaries(31623);
	for(int j = 0; j < primaries.size(); j++) printf("%d ", primaries[j]);
}


До миллиона за десятки мс генерит, если больше надо - тут алгоритмы посерьезнее http://habrahabr.ru/post/133037/
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918337
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вы меня испугали. Я уже подумал что нужно больше отдыхать, если я так сильно ошибался когда пытался решить данную задачу без дополнительных затрат статической памяти. Но это оказалось не так. Вообще говоря, Кнут(если не ошибаюсь) пишет примерно следующее: если число вариантов перебора менее 10! то можно использовать перебор. В данном конкретном случае, мы имели дело с простыми числами в диапазоне . Согласитесь, это немного. Потеря производительности была на другом участке кода, ниже рефакторинг с оптимизациями касаемо поиска простых чисел (они не играют решающую роль, можно оставить их как и прежде), и изменением в алгоритме Дмитрия

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
#include <stdio.h>
#include <math.h>

//assume x>1
int isPrime(int x)
{
	for (int i = 3; i <= sqrtl((long double)x); i+=2){
		if (x%i == 0)    return 0;
	}
	if (x % 2 == 0)    return 0;
	return 1;
}

int get_next_prime(int cur_pr)
{
	if (cur_pr == 2)	return 3;
	while (1){
		cur_pr += 2;
		if (isPrime(cur_pr))	return cur_pr;
	}
}

int count_op_from_Dima(int y, int x)
{
	if (x == y) return 0;
	if (x == 0 || y == 0 || y % x != 0 || y / x < 0) return -1;
	int a = y / x;
	
	int res = 0;
	int pr = 2;
	while (a > 1 && pr<=sqrt((float)a)) {
		if (a % pr == 0) {
			a /= pr;
			res += pr;
		}
		else {
			pr = get_next_prime(pr);
		}
	}
	if (a > 0) res += a;
	return res;

}


int main()
{
	int z, s;
	FILE* in = freopen("input.txt", "r", stdin);
	scanf("%i %i", &s, &z);
	fclose(in);
	FILE* out = freopen("output.txt", "w", stdout);
	printf("%i", count_op_from_Dima(z, s));
	fclose(out);
	return 0;
}
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918340
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не удержался C:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
//assume x>1
int isPrime(int x)
{
	for (int i = 3; i <= sqrtl((long double)x); i+=2){
		if (x%i == 0)    return 0;
	}
	return x % 2;
}
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918353
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хотя если так подумать, это не изменения в алгоритме Дмитрия(ибо его алгоритм предназначен для таблицы простых числе куда может входить число а), а модификация алгоритма для решения задачи без статической таблицы
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918358
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
От моего алгоритма только каркас остался :) Еще была версия m_Sla 17433850

Это лишнее
Код: plaintext
1.
if (a > 0) res += a;


a всегда больше 0

и sqrtl((long double)x) не панацея: от того что точность повышаешь она идеальной не становится, нет гарантии что корень из 9 не получится 2.999999999999999 и приведется к 2, я бы так писал
Код: plaintext
1.
sqrt((float)x) + 1
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918362
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я выше ссылки на статью про генераторы давал, не почитал? Там хорошая мысль была как корни не считать.
Это
Код: plaintext
1.
i <= sqrtl((long double)x)


равносильно этому
Код: plaintext
1.
i*i <= x


В принципе ничего гениального, но все считают корни.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918388
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, сравнивать нет смысла, строчка лишняя. Можно сравнивать произведение, знаю об этом.
Ознакомился с информацией по ссылкам, спасибо :) но т.к. я этой проблемой глубоко не занимаюсь, и пока не планирую, не стал углубляться. Решето Эратосфена мне знакомо давно. Аткина, в общих чертах знал, сейчас посмотрел ещё раз )
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918485
RWolf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

более того, такой for вообще ересь — условие выхода из цикла считается заново каждую итерацию, при том, что оно не меняется.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918539
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RWolfболее того, такой for вообще ересь — условие выхода из цикла считается заново каждую итерацию, при том, что оно не меняется.
В целом согласен, но в данном случае корень тоже считается каждую итерацию, но наверно компилятор это оптимизирует.

В принципе цикл можно соптимизировать расчетом последовательности квадратов:
Код: plaintext
1.
2.
3.
4.
5.
x = 1;
x2 = 1;
while(x < ...) {
x2 += 2*x + 1;
x++;}
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918558
RWolf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

простой тест:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
int count_op(int z)
{
  int x=1;
  for (int i=0; i<sqrt(z);i++)
    x*=2;
  return x;
}



gcc -std=c99 -O2 -S 1.c .globl _count_op
.def _count_op; .scl 2; .type 32; .endef
_count_op:
LFB39:
.cfi_startproc
pushl %esi
.cfi_def_cfa_offset 8
.cfi_offset 6, -8
pushl %ebx
.cfi_def_cfa_offset 12
.cfi_offset 3, -12
subl $36, %esp
.cfi_def_cfa_offset 48
xorl %ebx, %ebx
movl $1, %esi
fildl 48(%esp)
fstpl 16(%esp)
jmp L4
.p2align 2,,3
L5:
sall %esi
incl %ebx
L4:
fldl 16(%esp)
fstpl (%esp)
call _sqrt
movl %ebx, 28(%esp)
fildl 28(%esp)
fxch %st(1)
fucompp
fnstsw %ax
testb $69, %ah
je L5
movl %esi, %eax
addl $36, %esp
.cfi_def_cfa_offset 12
popl %ebx
.cfi_restore 3
.cfi_def_cfa_offset 8
popl %esi
.cfi_restore 6
.cfi_def_cfa_offset 4
ret
.cfi_endproc

call _sqrt в каждой итерации, хотя, казалось бы, оптимизация включена.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918582
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Понравилась идея SashaMercury с get_next_prime(), переделал немного свой генератор 17434730
Расчет следующего простого с кэшем
Заменил глобальный массив на static и добавил дописывание кэша по необходимости
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
#include <stdio.h>
#include <vector>

// следующее простое после x
int next_prime(int x)
{
	static std::vector<int> cache;
	static int max_prime = 0;
	if(max_prime == 0) {
		cache.push_back(2);
		cache.push_back(3);
		max_prime = 3;
	}
	if(x >= max_prime) { // нет в кэше
		for(int i = max_prime + 2; x >= max_prime; i += 2) {
			int* k = &cache[0];
			for(int j = cache.size(); j > 0 && i % *k != 0; j--,k++) {
				if(*k * *k > i) {
					cache.push_back(i);
					max_prime = i;
					break;
				}
			}
		}
		return max_prime;
	} else if(x < 2) {
		return 2;
	} else { // поиск в кэше
		int* min = &cache[0];
		int* max = &cache[cache.size() - 1];
		while(max - min > 1) {
			int* mid = min + (max - min) / 2;
			if (*mid > x) {
				max = mid;
			} else {
				min = mid;
			}
		}
		return *max;
	}
}

void  main(){
	int x = 0;
	for(int i = 0; i <100; i++) {
		x = next_prime(x);
		printf("%d ", x);
	}
	printf("%d\n", next_prime(-3));
}


До миллиона быстро генерит. Может кому пригодится. Я уже не раз качал таблицы, шаманил с форматированием чтоб в код вставить.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38918617
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Только производная от квадратного корня имеет другой вид.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919046
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RWolfDima T,

простой тест:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
int count_op(int z)
{
  int x=1;
  for (int i=0; i<sqrt(z);i++)
    x*=2;
  return x;
}



gcc -std=c99 -O2 -S 1.c .globl _count_op
.def _count_op; .scl 2; .type 32; .endef
_count_op:
LFB39:
.cfi_startproc
pushl %esi
.cfi_def_cfa_offset 8
.cfi_offset 6, -8
pushl %ebx
.cfi_def_cfa_offset 12
.cfi_offset 3, -12
subl $36, %esp
.cfi_def_cfa_offset 48
xorl %ebx, %ebx
movl $1, %esi
fildl 48(%esp)
fstpl 16(%esp)
jmp L4
.p2align 2,,3
L5:
sall %esi
incl %ebx
L4:
fldl 16(%esp)
fstpl (%esp)
call _sqrt
movl %ebx, 28(%esp)
fildl 28(%esp)
fxch %st(1)
fucompp
fnstsw %ax
testb $69, %ah
je L5
movl %esi, %eax
addl $36, %esp
.cfi_def_cfa_offset 12
popl %ebx
.cfi_restore 3
.cfi_def_cfa_offset 8
popl %esi
.cfi_restore 6
.cfi_def_cfa_offset 4
ret
.cfi_endproc

call _sqrt в каждой итерации, хотя, казалось бы, оптимизация включена.


странно, z в теле цикла не меняется в данном конкретном случае. По хорошему должен оптимизировать. Может быть есть квалификатор обратный к volitile ?
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919050
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonТолько производная от квадратного корня имеет другой вид.

Марк, можно подробнее причём тут производная, для особо одарённых :D
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919051
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А откуда оптимизатору знать что sqrt - это чистая функция, которая зависит только от аргументов?
А без этого знания ни о каком предварительном вычислении не может быть и речи.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919056
RWolf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercury,

Просто компилятор не знает, что sqrt() не имеет побочных эффектов, и поэтому не может выкинуть лишние вызовы.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919059
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyА откуда оптимизатору знать что sqrt - это чистая функция, которая зависит только от аргументов?
А без этого знания ни о каком предварительном вычислении не может быть и речи.

а нет оптимизаций во время выполнения программы ?
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919072
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryа нет оптимизаций во время выполнения программы ?
Нет. А как бы это помогло? :)
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919077
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно оптимизатору помочь иногда
Код: plaintext
1.
2.
int max = sqrt(z);
for (int i=0; i<max;i++)


или так (если направление не важно)
Код: plaintext
1.
for (int i=sqrt(z); i>=0;i--)
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919089
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskySashaMercuryа нет оптимизаций во время выполнения программы ?
Нет. А как бы это помогло? :)

Видимо никак.
Если бы компилятор знал о том что у этой функции нет побочных эффектов, и аргументы не меняются в теле цикла, он мог бы оптимизировать.

Впрочем, Дмитрий предложил хороший вариант, который будет применим и для других аналогичных ситуаций
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919233
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Думайте шЫрше.

Мы можем (грубо) заменить параболу на последовательность кусочно-линейных функций.
И это будет выигрыш. Главное чтоб эти кусочки были больше либо равны параболе.

Весь вопрос в выборе шага. Побочный эффект - парочка "лишних" делений. Которые на результат
не влияют.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919262
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonМы можем (грубо) заменить параболу на последовательность кусочно-линейных функций.
И это будет выигрыш. Главное чтоб эти кусочки были больше либо равны параболе.
В данном случае можно вообще таблицей в пару тысяч значений.

Вопрос будет ли оно быстрее умножения?

На своем генераторе затестил 17438916
заменил умножение в цикле
Код: plaintext
1.
2.
for(int j = cache.size(); j > 0 && i % *k != 0; j--,k++) {
	if(*k * *k > i) {


на корень перед циклом
Код: plaintext
1.
2.
3.
int i2= sqrt((float)i);
for(int j = cache.size(); j > 0 && i % *k != 0; j--,k++) {
	if(*k > i2) {


Умножение в цикле быстрее.
next_prime(10 000 000)
с умножением 741 мс
с корнем 851 мс
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919277
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
посчитал в разах:
корней 5`000`008
умножений 277`474`804

Т.е. если на расчет потребуется меньше 55 умножений, то выгодно. Теоретически должно взлететь.
...
Рейтинг: 0 / 0
Решение одной задачи
    #38919409
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Прямые рисовать не стал, пошел другим путем, т.к. i у меня возрастает:
Код: plaintext
1.
2.
3.
4.
5.
int qi = 1;
for(int i = max_prime + 2; x >= max_prime; i += 2) {
	while(qi * qi < i) qi++; // ближайшее большее целое корня i
	for(int j = cache.size(); j > 0 && i % *k != 0; j--,k++) {
		if(*k > qi) {


Т.е. умножений стало на 270 млн. меньше. ИМХУ самый оптимальный вариант.
Ничего не изменилось, т.е. 270 млн. умножений занимают меньше 10 мс (дискретность таймера).


Интересный прикол, переключился в debug, такой код работает 1610 мс
Код: plaintext
1.
2.
3.
4.
5.
int qi = 1;
for(int i = max_prime + 2; x >= max_prime; i += 2) {
	//while(qi * qi < i) qi++; // ближайшее большее целое корня i
	for(int j = cache.size(); j > 0 && i % *k != 0; j--,k++) {
		if(*k * *k > i) {


а если while() разремить то 1550 мс, т.е. лишние циклы ускоряют программу

ХЗ кто помог, компилятор по другому регистры использовал или внутри проца какая-то оптимизация случилась. Затестил раз на десять. Стабильно проявляется в дебаге. Хорошо хоть в релизе нет.
...
Рейтинг: 0 / 0
25 сообщений из 76, страница 3 из 4
Форумы / C++ [игнор отключен] [закрыт для гостей] / Решение одной задачи
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]