читайте тему с начала, обсуждалось ужеSheen писал(а):Ну да, согласен, фигня получается ... так может тогда завести одну маленькую (а можно и побольше) переменную и при добавлении значения в массив, если значение нулевой, помещать на него ссылку. Когда надо будет это нулевое значение вытащить ... [лень набирать дальше]
Массив с нулём
Правила форума
Пожалуйста, ознакомьтесь с правилами данного форума
Пожалуйста, ознакомьтесь с правилами данного форума
- Аман Ванкуверский
- Маньяк
- Сообщения: 2759
- Зарегистрирован: 18 окт 2005, 01:10
- Аман Ванкуверский
- Маньяк
- Сообщения: 2759
- Зарегистрирован: 18 окт 2005, 01:10
пусть сенсеи меня поправят, но в теории задача оптимизации это уменшить степень функции О(N), где O - время затраченное на выполнение функции в зависимости от количества элементов N. При этом константа C (т.е. в данном случае t1, t2/2) отбрасывается. оба способа, соответственно имеют O(N) = N, т.е. среднее время выполнения линейно растет с увеличением кол-ва элементов.Azazello писал(а): Способ #1: пробежать весь массив, скажем, перемножая элементы, и результат сравнить с нулём. Время на работу с одним элементом - t1. Время на выполнение ВСЕГДА - N*t1.
Способ #2: loop с выходом, если элемент равен нулю. Время на работу с одним элементом - t2. Какое, в среднем, время мы потратим на поиск нуля в произвольном элементе? На вскидку, N(1 + N)*t2/2N =~ N*t2/2.
Вывод: Если я не ошибся, пробег всего массива выгоден только если t1 < t2/2.
для логической оптимизации соответственно нужно превратить это дело, например, в O(N) = sqrt(N). O(N) = C можно добиться, храня значение ячейки отдельно, но тогда время функции добавления в массив вырастает с 1 до N. но так всегда - выигрываешь в одном - проигрываешь в другом.
для практической оптимизации видимо желательно хотя бы уменшить коэффициент при линейно растущем N. и тут, если я правильно усвоил лекции sz, пойнт в том, что на современных процах быстрее линейно прокрутить for, чем сравнивать значения переменных, даже если цикл законится раньше
это такой небольшой summary
am i missing something?
- Azazello
- Житель
- Сообщения: 769
- Зарегистрирован: 16 янв 2007, 04:31
Аман, в N/2 двойка в знаменателе - следствие того, что у нас только ОДИН ноль в массиве. Тривиальный случай - все элементы массива равны нулю. Тогда Способ #2 будет ВСЕГДА занимать ровно одну операцию, в то время как способ #1 будет, по-прежнему, ВСЕГДА занимать N операций. Во втором способе число операций пропорционально не просто N, а некому отношению N к числу нулей в массиве (4 утра, я только домой вернулся - лень считать
... Типа, что-нибудь обратно пропорциональное "цэ из эн по ка" - число сочетаний... точнее завтра напишу
...).
-
i_van
- Завсегдатай
- Сообщения: 251
- Зарегистрирован: 09 сен 2004, 23:58
В данном конкретном случае упоминалось, что наличие 0 маловероятно. Так что об N/2, возникающем из-за прерывания цикла, или числе комбинаций можно забыть. Остается лишь сравнить t1 и t2. Еще вспоминаем, что это embedded system. Поэтому я думаю, что это все же вопрос стоимости операции (операций) при полном проходе по циклу.Azazello писал(а):Аман, в N/2 двойка в знаменателе - следствие того, что у нас только ОДИН ноль в массиве. Тривиальный случай - все элементы массива равны нулю. Тогда Способ #2 будет ВСЕГДА занимать ровно одну операцию, в то время как способ #1 будет, по-прежнему, ВСЕГДА занимать N операций. Во втором способе число операций пропорционально не просто N, а некому отношению N к числу нулей в массиве (4 утра, я только домой вернулся - лень считать... Типа, что-нибудь обратно пропорциональное "цэ из эн по ка" - число сочетаний... точнее завтра напишу
...).
А вот предложение сравнивать элементы попарно может дать N/2.
-
tiasur
- Маньяк
- Сообщения: 1510
- Зарегистрирован: 26 фев 2006, 10:00
- Откуда: offline
Попробовал я тот код. Не работает. Идею не уловил, вернее я согласен, что хорошо бы использовать поразрядные операции, но ... казалось вот она идея, а посмотрел поближе - фиг. Как с вечным двигателем.sz писал(а):Сравнение двух чисел и проверка на 0 - одна фигня.tiasur писал(а):Мне кажется правильным решением будет найти наименьшее число массива и затем сравнить его с нулем. Сравнение двух чисел идёт быстрее, чем проверка на нуль? В задаче не сказано, что в массиве могут быть орицательные числа.
Но можно использовать функцию min(abs(*a)). Правильные их имплементации не содержат никаких ифов.
Но вообще-то, тот код, который я ранее написал полностью и правильно отвечает на вопрос. Я абсолютно уверен, что это именно то, что они ждут.
- ajkj3em
- Маньяк
- Сообщения: 2063
- Зарегистрирован: 12 ноя 2006, 06:53
-
tiasur
- Маньяк
- Сообщения: 1510
- Зарегистрирован: 26 фев 2006, 10:00
- Откуда: offline
Не помогло. Совсем запарил себе мозги - не фига не работает.ajkj3em писал(а):v ^ ~(v-1) равно 0 if and only if v равно 0tiasur писал(а):Попробовал я тот код. Не работает. Идею не уловил, вернее я согласен, что хорошо бы использовать поразрядные операции, но ... казалось вот она идея, а посмотрел поближе - фиг. Как с вечным двигателем.
то есть sz ~ пропустил
зачем это выражение, если v и без него равно 0 когда оно равно 0? Извиняюсь за тафтологию.v ^ ~(v-1) равно 0 if and only if v равно 0
- ajkj3em
- Маньяк
- Сообщения: 2063
- Зарегистрирован: 12 ноя 2006, 06:53
логично :)tiasur писал(а):зачем это выражение, если v и без него равно 0 когда оно равно 0? Извиняюсь за тафтологию.v ^ ~(v-1) равно 0 if and only if v равно 0
короче, вот правильный ответ -
Код: Выделить всё
#include <limits.h>
int check_for_zero(int * v, size_t n)
{
int r = 0;
for (; n; v++, n--) r |= ~( (*v) | -(*v) );
return (r >> (CHAR_BIT * sizeof(int) - 1)) & 1;
}
PPS фишка в том, что (x | -x) выставляет highest бит для всех значений x кроме нуля. дальше я думаю все очевидно ..
-
tiasur
- Маньяк
- Сообщения: 1510
- Зарегистрирован: 26 фев 2006, 10:00
- Откуда: offline
Красивая идея. Похоже что работает - нужно еще раз продумать.ajkj3em писал(а): короче, вот правильный ответ -
PS вообще без сравнений кстати (кроме for условия)Код: Выделить всё
#include <limits.h> int check_for_zero(int * v, size_t n) { int r = 0; for (; n; v++, n--) r |= ~( (*v) | -(*v) ); return (r >> (CHAR_BIT * sizeof(int) - 1)) & 1; }
PPS фишка в том, что (x | -x) выставляет highest бит для всех значений x кроме нуля. дальше я думаю все очевидно ..
Думаю что можно сократить на пару операций:
Код: Выделить всё
#include <limits.h>
int check_for_zero(int * v, size_t n)
{
int r = ~0;
for (; n; v++, n--) r &= (*v) | -(*v);
return (r == 0);
}
- ajkj3em
- Маньяк
- Сообщения: 2063
- Зарегистрирован: 12 ноя 2006, 06:53
tiasur писал(а):Есть замечания?
Код: Выделить всё
return (r >> (CHAR_BIT * sizeof(int) - 1)) == 0;-
tiasur
- Маньяк
- Сообщения: 1510
- Зарегистрирован: 26 фев 2006, 10:00
- Откуда: offline
Мне кажется он излишен.ajkj3em писал(а):tiasur писал(а):Есть замечания?Код: Выделить всё
return (r >> (CHAR_BIT * sizeof(int) - 1)) == 0;
Что-то не догоняю?
- ajkj3em
- Маньяк
- Сообщения: 2063
- Зарегистрирован: 12 ноя 2006, 06:53
-
tiasur
- Маньяк
- Сообщения: 1510
- Зарегистрирован: 26 фев 2006, 10:00
- Откуда: offline
- sz
- Маньяк
- Сообщения: 1266
- Зарегистрирован: 17 фев 2003, 19:34
Ошибка в другом месте. В конце надо сравнивать с 0xffffffff, а не с нулем. Ну и с начальными значениями ошибся. Виноват.ajkj3em писал(а):v ^ ~(v-1) равно 0 if and only if v равно 0tiasur писал(а):Попробовал я тот код. Не работает. Идею не уловил, вернее я согласен, что хорошо бы использовать поразрядные операции, но ... казалось вот она идея, а посмотрел поближе - фиг. Как с вечным двигателем.
то есть sz ~ пропустил
bool HasZeroes( const unsigned* array, unsigned size )
{
unsigned result = 0;
for( ; size != 0; --size,++array ) result |= *array-1^*array;
return result == 0xffffffff;
}
Идея была в том, что (i-1)^i всегда дает степень двойки минус один - 1, 3, 7, 15 и тд. Причем 0xffffffff только для 0.
Но можно и i|-i - тоже нормально.
- ajkj3em
- Маньяк
- Сообщения: 2063
- Зарегистрирован: 12 ноя 2006, 06:53
не работает если массив состоит из всех степеней двойкиsz писал(а): Идея была в том, что (i-1)^i всегда дает степень двойки минус один - 1, 3, 7, 15 и тд. Причем 0xffffffff только для 0.
(edit) вернее, если i = 0x80000000
Последний раз редактировалось ajkj3em 26 мар 2007, 11:20, всего редактировалось 3 раза.