Массив с нулём

Все, что вы хотели знать о программизме, но боялись спросить.
Ответить
Аватара пользователя
Аман Ванкуверский
Маньяк
Сообщения: 2759
Зарегистрирован: 18 окт 2005, 01:10

Сообщение Аман Ванкуверский »

Sheen писал(а):Ну да, согласен, фигня получается ... так может тогда завести одну маленькую (а можно и побольше) переменную и при добавлении значения в массив, если значение нулевой, помещать на него ссылку. Когда надо будет это нулевое значение вытащить ... [лень набирать дальше]
читайте тему с начала, обсуждалось уже ;)
Аватара пользователя
Аман Ванкуверский
Маньяк
Сообщения: 2759
Зарегистрирован: 18 окт 2005, 01:10

Сообщение Аман Ванкуверский »

Azazello писал(а): Способ #1: пробежать весь массив, скажем, перемножая элементы, и результат сравнить с нулём. Время на работу с одним элементом - t1. Время на выполнение ВСЕГДА - N*t1.
Способ #2: loop с выходом, если элемент равен нулю. Время на работу с одним элементом - t2. Какое, в среднем, время мы потратим на поиск нуля в произвольном элементе? На вскидку, N(1 + N)*t2/2N =~ N*t2/2.

Вывод: Если я не ошибся, пробег всего массива выгоден только если t1 < t2/2.
пусть сенсеи меня поправят, но в теории задача оптимизации это уменшить степень функции О(N), где O - время затраченное на выполнение функции в зависимости от количества элементов N. При этом константа C (т.е. в данном случае t1, t2/2) отбрасывается. оба способа, соответственно имеют O(N) = N, т.е. среднее время выполнения линейно растет с увеличением кол-ва элементов.

для логической оптимизации соответственно нужно превратить это дело, например, в O(N) = sqrt(N). O(N) = C можно добиться, храня значение ячейки отдельно, но тогда время функции добавления в массив вырастает с 1 до N. но так всегда - выигрываешь в одном - проигрываешь в другом.

для практической оптимизации видимо желательно хотя бы уменшить коэффициент при линейно растущем N. и тут, если я правильно усвоил лекции sz, пойнт в том, что на современных процах быстрее линейно прокрутить for, чем сравнивать значения переменных, даже если цикл законится раньше

это такой небольшой summary
am i missing something?
Аватара пользователя
Azazello
Житель
Сообщения: 769
Зарегистрирован: 16 янв 2007, 04:31

Сообщение Azazello »

Аман, в N/2 двойка в знаменателе - следствие того, что у нас только ОДИН ноль в массиве. Тривиальный случай - все элементы массива равны нулю. Тогда Способ #2 будет ВСЕГДА занимать ровно одну операцию, в то время как способ #1 будет, по-прежнему, ВСЕГДА занимать N операций. Во втором способе число операций пропорционально не просто N, а некому отношению N к числу нулей в массиве (4 утра, я только домой вернулся - лень считать ;)... Типа, что-нибудь обратно пропорциональное "цэ из эн по ка" - число сочетаний... точнее завтра напишу ;)...).
i_van
Завсегдатай
Сообщения: 251
Зарегистрирован: 09 сен 2004, 23:58

Сообщение i_van »

Azazello писал(а):Аман, в N/2 двойка в знаменателе - следствие того, что у нас только ОДИН ноль в массиве. Тривиальный случай - все элементы массива равны нулю. Тогда Способ #2 будет ВСЕГДА занимать ровно одну операцию, в то время как способ #1 будет, по-прежнему, ВСЕГДА занимать N операций. Во втором способе число операций пропорционально не просто N, а некому отношению N к числу нулей в массиве (4 утра, я только домой вернулся - лень считать ;)... Типа, что-нибудь обратно пропорциональное "цэ из эн по ка" - число сочетаний... точнее завтра напишу ;)...).
В данном конкретном случае упоминалось, что наличие 0 маловероятно. Так что об N/2, возникающем из-за прерывания цикла, или числе комбинаций можно забыть. Остается лишь сравнить t1 и t2. Еще вспоминаем, что это embedded system. Поэтому я думаю, что это все же вопрос стоимости операции (операций) при полном проходе по циклу.

А вот предложение сравнивать элементы попарно может дать N/2.
tiasur
Маньяк
Сообщения: 1510
Зарегистрирован: 26 фев 2006, 10:00
Откуда: offline

Сообщение tiasur »

sz писал(а):
tiasur писал(а):Мне кажется правильным решением будет найти наименьшее число массива и затем сравнить его с нулем. Сравнение двух чисел идёт быстрее, чем проверка на нуль? В задаче не сказано, что в массиве могут быть орицательные числа.
Сравнение двух чисел и проверка на 0 - одна фигня.
Но можно использовать функцию min(abs(*a)). Правильные их имплементации не содержат никаких ифов.
Но вообще-то, тот код, который я ранее написал полностью и правильно отвечает на вопрос. Я абсолютно уверен, что это именно то, что они ждут.
Попробовал я тот код. Не работает. Идею не уловил, вернее я согласен, что хорошо бы использовать поразрядные операции, но ... казалось вот она идея, а посмотрел поближе - фиг. Как с вечным двигателем.
Аватара пользователя
ajkj3em
Маньяк
Сообщения: 2063
Зарегистрирован: 12 ноя 2006, 06:53

Сообщение ajkj3em »

tiasur писал(а):Попробовал я тот код. Не работает. Идею не уловил, вернее я согласен, что хорошо бы использовать поразрядные операции, но ... казалось вот она идея, а посмотрел поближе - фиг. Как с вечным двигателем.
v ^ ~(v-1) равно 0 if and only if v равно 0

то есть sz ~ пропустил :)
tiasur
Маньяк
Сообщения: 1510
Зарегистрирован: 26 фев 2006, 10:00
Откуда: offline

Сообщение tiasur »

ajkj3em писал(а):
tiasur писал(а):Попробовал я тот код. Не работает. Идею не уловил, вернее я согласен, что хорошо бы использовать поразрядные операции, но ... казалось вот она идея, а посмотрел поближе - фиг. Как с вечным двигателем.
v ^ ~(v-1) равно 0 if and only if v равно 0

то есть sz ~ пропустил :)
Не помогло. Совсем запарил себе мозги - не фига не работает.

v ^ ~(v-1) равно 0 if and only if v равно 0
зачем это выражение, если v и без него равно 0 когда оно равно 0? Извиняюсь за тафтологию.
Аватара пользователя
ajkj3em
Маньяк
Сообщения: 2063
Зарегистрирован: 12 ноя 2006, 06:53

Сообщение ajkj3em »

tiasur писал(а):
v ^ ~(v-1) равно 0 if and only if v равно 0
зачем это выражение, если v и без него равно 0 когда оно равно 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;
}
PS вообще без сравнений кстати (кроме for условия) :)

PPS фишка в том, что (x | -x) выставляет highest бит для всех значений x кроме нуля. дальше я думаю все очевидно ..
tiasur
Маньяк
Сообщения: 1510
Зарегистрирован: 26 фев 2006, 10:00
Откуда: offline

Сообщение tiasur »

ajkj3em писал(а): короче, вот правильный ответ -

Код: Выделить всё

#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;
}
PS вообще без сравнений кстати (кроме for условия) :)

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

Сообщение ajkj3em »

tiasur писал(а):Есть замечания?

Код: Выделить всё

return (r >> (CHAR_BIT * sizeof(int) - 1)) == 0;
tiasur
Маньяк
Сообщения: 1510
Зарегистрирован: 26 фев 2006, 10:00
Откуда: offline

Сообщение tiasur »

ajkj3em писал(а):
tiasur писал(а):Есть замечания?

Код: Выделить всё

return (r >> (CHAR_BIT * sizeof(int) - 1)) == 0;
Мне кажется он излишен.
Что-то не догоняю?
Аватара пользователя
ajkj3em
Маньяк
Сообщения: 2063
Зарегистрирован: 12 ноя 2006, 06:53

Сообщение ajkj3em »

логично, излишен :)

* перевод с транслита
tiasur
Маньяк
Сообщения: 1510
Зарегистрирован: 26 фев 2006, 10:00
Откуда: offline

Сообщение tiasur »

Спасибо
Аватара пользователя
sz
Маньяк
Сообщения: 1266
Зарегистрирован: 17 фев 2003, 19:34

Сообщение sz »

ajkj3em писал(а):
tiasur писал(а):Попробовал я тот код. Не работает. Идею не уловил, вернее я согласен, что хорошо бы использовать поразрядные операции, но ... казалось вот она идея, а посмотрел поближе - фиг. Как с вечным двигателем.
v ^ ~(v-1) равно 0 if and only if v равно 0

то есть sz ~ пропустил :)
Ошибка в другом месте. В конце надо сравнивать с 0xffffffff, а не с нулем. Ну и с начальными значениями ошибся. Виноват.

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

Сообщение ajkj3em »

sz писал(а): Идея была в том, что (i-1)^i всегда дает степень двойки минус один - 1, 3, 7, 15 и тд. Причем 0xffffffff только для 0.
не работает если массив состоит из всех степеней двойки

(edit) вернее, если i = 0x80000000
Последний раз редактировалось ajkj3em 26 мар 2007, 11:20, всего редактировалось 3 раза.
Ответить