LINUX.ORG.RU
Ответ на: комментарий от anonymous

> я все-таки продолжу агент666, если нужна функция long double avg(long doublea, long double b), что будешь делать?

long double avg(long double a, long double b)
{
return a*0.5 + b*0.5;
}

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

Agent666
()
Ответ на: комментарий от generatorglukoff

> Учитывая что переводе long long -> float можно потерять точность

Да, я согласен. Я лучше сразу возьму float вместо long long, чтобы не было риска переполнения, чем буду лепить квадратные колёса к велосипеду.

> а решение - по типу "не хватает памяти? ну купи еще 4 гигабайта, или ты нищеброд?"

Вопрос совсем не в этом, а в том, чтобы сделать код максимально понятным.

Agent666
()
Ответ на: комментарий от Agent666

> Да, я согласен. Я лучше сразу возьму float вместо long long, чтобы не было риска переполнения, чем буду лепить квадратные колёса к велосипеду.

а тот long long был индексом в массиве в котором искали бинарным поиском..

dilmah ★★★★★
()
Ответ на: комментарий от Agent666

> Я лучше сразу возьму float вместо long long, чтобы не было риска переполнения, чем буду лепить квадратные колёса к велосипеду.

Хотя опять же уткнусь в ту же точноть... Ну да, тут может и понадобиться тот костыль.
Но в случае с int он явно ни к чему.

Agent666
()
Ответ на: комментарий от Agent666

Это ничем не лучше (a+b)/2. И то и то работает в некоторых случаях неправильно, а с float еще и медленней будет. С float'ами еще будет охрененная потеря точности (ты 64х битное целое пытаешь преобразовать в 32х битный float)

Reset ★★★★★
()
Ответ на: комментарий от Agent666

Вы все не Ъ, ибо Ъ пишут так:

avg :: Integer -> Integer -> Integer
avg a b = (a+b)/2

и получают код, который 
a) понятен и читабелен
b) работает корректно для любых входных a и b (при услови что 
оперативи хватит на представление a, b, промежуточных данных и 
результата, вместе взятых).

fmj
()
Ответ на: комментарий от Reset

> а с float еще и медленней будет

Не будет. Умножение float-ов выполняется за 3 такта, деление целых - порядка 20 тактов.
С 64-битными ещё больше.

> С float'ами еще будет охрененная потеря точности (ты 64х битное целое пытаешь преобразовать в 32х битный float)

С этим я уже согласился, смотри выше.

Agent666
()
Ответ на: комментарий от Agent666

> деление целых - порядка 20 тактов.

компилятор заменит /2 для целого числа на арифметический сдвиг, который 1 такт.

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

> компилятор заменит /2 для целого числа на арифметический сдвиг, который 1 такт.

Не заменит, потому что для отрицательного числа получится неправильный результат.

Agent666
()
Ответ на: комментарий от Agent666

доктор, что я делаю не так? 

$ cat > 1.c
#include <stdio.h>
int main()
{
     int i = -10;
     i >>= 1;
     printf("%d\n", i);
}
ctlr+d
$ make 1
gcc 1.c -o 1
$ ./1
-5

Древний gcc 3.4.2

fmj
()
Ответ на: комментарий от anonymous

> По результатам топика, могу сказать агенту 666 только одно: ¡ВОН ИЗ ПРОФЕССИИ!

Критика твоя не конструктивная, и поэтому меня не волнует.

Agent666
()
Ответ на: комментарий от fmj

>доктор, что я делаю не так?

очевидно:
1. понимаете действие оператора сдвига (арифметического)
2. представление отрицательных чисел

generatorglukoff ★★
()
Ответ на: комментарий от Agent666

> Любой код, который при одинаковой функциональности сложнее, не является хорошим (если, конечно, тут нет критичных требований к скорости выполнения; а его код ещё и медленнее будет работать).

Умоляю, забудь про Це, пиши на Тикле (в крайнем случае, на Жабке)!

Перевод int-> float-> int во избежание промежуточных переполнений может позволить себе только программист на Васике. Да, да, оно будет короче и работать будет быстрее; и, скорее всего, копейки в конце сойдутся -- не всегда, но пусть об этом у бухгалтера голова болит!! :-)

Die-Hard ★★★★★
()
Ответ на: комментарий от fmj

Значит я ошибался. Я вот, что имел ввиду, когда написал, что результат будет неправильный:

Например, i = -16 = 11111110b (играничусь 8-ми разрядным знаковым).

i >>= 1 = 01111111b != -8

Получается, компилятор учитывает знак.

Agent666
()
Ответ на: комментарий от Die-Hard

> Умоляю, забудь про Це,

Бога умоляй

> Перевод int-> float-> int во избежание промежуточных переполнений может позволить себе только программист на Васике.

Вы сами это правило придумали?

Agent666
()
Ответ на: комментарий от Die-Hard

И про float я уже признал, что был не прав, что ж вы все читать-читаете, а ничего не видите.
Но предложение с int->long long по-прежнему в силе

Agent666
()
Ответ на: комментарий от Agent666

>> Перевод int-> float-> int во избежание промежуточных переполнений может позволить себе только программист на Васике.

> Вы сами это правило придумали?

Пардон, не ковырять в носу за обедом -- какой "умник" придумал это правило? Явно же калории теряются в холостую, и на пустом месте лишний соус потребен! ;)

Die-Hard ★★★★★
()
Ответ на: комментарий от Agent666

> Не заменит, потому что для отрицательного числа получится неправильный результат.

почитай что такое арифметический сдвиг

dilmah ★★★★★
()
Ответ на: комментарий от generatorglukoff

> Любой код, который не работает в не которых ситуациях, всегда хуже того, который работает всегда.

Зависит от критерия "худшести/лучшести" кода. В любом производстве, в том числе и в программировании многое решает время, потраченное на разработку. Ложка дорога к обеду. Поэтому всегда наиболее рационально соблюдать компромисс между затраченными усилиями и качеством полученного кода. Перфекционизм вреден.

Burbaka ★★
()
Ответ на: комментарий от Burbaka

>Зависит от критерия "худшести/лучшести" кода. В любом производстве, в том числе и в программировании многое решает время, потраченное на разработку. Ложка дорога к обеду. Поэтому всегда наиболее рационально соблюдать компромисс между затраченными усилиями и качеством полученного кода. Перфекционизм вреден.

К сожалению, это правда.

generatorglukoff ★★
()
Ответ на: комментарий от Die-Hard

Статья не нова, но почитать было интересно :)

JackYF ★★★★
()

поэтому и говорят умные люди, что императив сосёт, функциональные языке роляд

anonymous
()
Ответ на: комментарий от generatorglukoff

> очевидно:

> 1. понимаете действие оператора сдвига (арифметического)

> 2. представление отрицательных чисел

гм, ну я то как раз прекрасно понимаю, как работает арифметический сдвиг, а вот агент 666 с трудом вкуривает, это я и пытался показать, а если вы не заметили иронии в моем сообщении, то отвлекитесь на пару часов от компа, и просто прогуляйтесь на свежем воздухе, весна все-же, -- заработались вы голубчик

fmj
()

Кстати, по поводу примера полого/хорошего кода, нужно так-же хорошо 
представлять, где будет использоватся код. Вот тот-же пример с "правильной" avg 
конечно хорош, тем что не будет использовать двойную разрядность для хранения 
тех-же int-ов, но с другой стороны, он может быть в разы медленнее чем код, 
использующий промежуточное long long (или просто int64_t) представление. Да, да, 
верно, из-за 3х ветвлекий на каждый вызов avg, вместо полной линейности в long long 
варианте. И если в коде много математики целочисленной с avg-ами, + 
неоднородные данные, то long long явно будет в несколько раз быстрее работать.

Не поленился, изобразил тест-кейс

enum { NR = 1024*1024 };
enum { ITER = 1000 };


int inp[NR];

// И без того упрощенная функция, для повышения скорости работы.

int qsign(int a)
{
	return  a > 0 ? 1 : -1;
}

int avg1(int a, int b)
{
	if (qsign(a) != qsign(b))
		return (a+b)/2;
	else
		return (a + (b-a)/2);
}

int avg2(int a, int b)
{
	long long _a = a, _b = b;
	return (_a + _b)/2;
}

int main()
{
	int i;

	for (i=0; i<NR; i++)
	{
		inp[i] = rand()  - (RAND_MAX/2);
	}

	time_t st1 = time(NULL);

	for (int j = 0; j < ITER; j++)
		for (i=0; i<NR-1; i++)
		{
			static volatile int t;
			t = avg1(inp[i], inp[i+1]);
		}

	time_t st2 = time(NULL);

	for (int j = 0; j < ITER; j++)
		for (i=0; i<NR-1; i++)
		{
			static volatile int t;
			t = avg2(inp[i], inp[i+1]);
		}

	time_t st3 = time(NULL);

	printf("%d vs %d\n", st2-st1, st3-st2);
}

в итоге, 13 vs 6 секунд при компилянии с -O9 на C2D 1.6. 

Если же "- (RAND_MAX/2);" закомментирвоать, то результаты моментально 
выравниваются, блоки предсказаний переходов начинает угадывать результат 
корректно, что еще раз подтверждает правило: 
решение должно соответствовать задаче, а не быть правильным по каким-то
общевселенским критериям правильности.

fmj
()
Ответ на: комментарий от fmj

Хотя ассаемблерный листинг показывает, что от ветвлений, при вычислении sign-а, компилятор избавляется.

fmj
()
Ответ на: комментарий от fmj

>>а если вы не заметили иронии в моем сообщении, то отвлекитесь на пару часов от компа, и просто прогуляйтесь на свежем воздухе, весна все-же, -- заработались вы голубчик

если вы не заметили, что generatorglukoff вас _поддержал_, то отвлекитесь на пару часов от компа, и просто прогуляйтесь на свежем воздухе, весна все-же, -- заработались вы голубчик :)

Кстати насчёт весны, не знаю как в России, у нас ещё снег лежит сантиметров пятнадцать..

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

У нас уже почти все растаяло, хотя снега было дофигищи в самарской области, метра по полтора сугробы

fmj
()
Ответ на: комментарий от anonymous

умножать числа - оригинально :)

#define qsign(a) (a > 0 ? 1 : -1)

alex_custov ★★★★★
()
Ответ на: комментарий от fmj

> ну я то как раз прекрасно понимаю, как работает арифметический сдвиг, а вот агент 666 с трудом вкуривает,

Признаться, к своему стыду, я полагал, что в C сдвиг логический, а не арифметический.
Что ж, это повод повнимательнее почитать стандарт.

Agent666
()
Ответ на: комментарий от Agent666

Ничего, бывает, там сдвиг вправо для беззнаковых логический, а для знаковых арифметический.

anonymous
()
Ответ на: комментарий от Agent666

>long long avg(long long a, long long b)
>{
>float res = ((float)a + b) * 0.5;
>return (long long)res;
>}

А ты прикольный:-)
Скажи, а сколько бит отводится под мантиссу? И сколько под тип long long?

anonymous
()
Ответ на: комментарий от Agent666

>Не будет. Умножение float-ов выполняется за 3 такта, деление целых - порядка 20 тактов.

Я гоню или современные интеловские процессоры всё-таки в один такт укладываются?

WFrag ★★★★
()
Ответ на: комментарий от WFrag

> Я гоню или современные интеловские процессоры всё-таки в один такт укладываются?

по латентности не укладываются.. иначе конвейер был не нужен..

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

> по латентности не укладываются.. иначе конвейер был не нужен..

FPU вроде как тоже без конвейра в 3 такта не уложится

fmj
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.