Попытка взять среднее значение определенной части начала и конца массива - PullRequest
0 голосов
/ 06 февраля 2019

Следующая проблема выполняется на ПЛК, полностью написанном на C. Эта функция является частью библиотеки, которую я попытался добавить.

У меня есть массив данных произвольной длины.Следующий код срабатывает, когда длина массива> = 25 записей.Эта функция должна определять первый и последний x процентов записей (т.е. 33% массива из 99 будут первыми и последними 33 записями).Первая и последняя части затем усредняются и сжимаются в две половины (или половину +/- 1 в случае нечетных входных массивов).Окончательный результат представляет собой комбинацию этих двух массивов.

Для этой цели я пытаюсь сделать функцию этой формы:

plcbit arrayCompressFloatExtremities(float* arrayToCopyResultTo,
        float* arrayToDecrease, unsigned long numberOfDesiredElements,
        unsigned long numberOfElementsInOriginal, float inclusionZonePercent)

где

  • float* arrayToCopyResultTo - это мой целевой массив после завершения функции
  • float* arrayToDecrease - указатель входного массива
  • unsigned long numberofDesiredElements - длина выходного массива, должна быть 25
  • unsigned long numberofElementsInOriginal - это длина исходного массива,> = 25
  • float inclusionZonePercent - это процент от переднего и заднего конца массива, который я хочу сжать.Например, ввод значения .25 будет сжимать первые 25% и последние 25% записей в массив 25 записей длиной

Пока что кажется, что код работает до определенной точки.Однако в моем отладчике значение usedInterval делится на ноль, и я не уверен почему.Несмотря на это, я не уверен, что установил это правильно.

/* compresses and compies the array while neglecting a certain percentage of the board */
plcbit arrayCompressFloatExtremities(float* arrayToCopyResultTo,
        float* arrayToDecrease, unsigned long numberOfDesiredElements,
        unsigned long numberOfElementsInOriginal, float inclusionZonePercent) {
    int usedInterval = 0, i = 0, j = 0, k = 0, numberOfElementsLeft = 0;
    double temp = 0;
    float zone = 0;

    if ((numberOfElementsInOriginal == 0) || (numberOfDesiredElements == 0)) return 0;

    // determine zone size
    numberOfElementsInOriginal = sizeof(arrayToDecrease);
    numberOfElementsLeft = numberOfElementsInOriginal * inclusionZonePercent;

    // compress zone A into first half of output array using modulo operator
    // for odd number arrays

    for (i = 0;
            i < ((numberOfDesiredElements - (numberOfDesiredElements % 2)) / 2);
            i++) // i starts at 0 for the beginning part of the board and continues until the halfway point or halfway - 1
    {
        usedInterval = numberOfElementsLeft /
                (((numberOfDesiredElements - (numberOfDesiredElements % 2)) / 2) - i); 
        temp = 0;
        for (j = 0;
                j < (usedInterval + numberOfElementsInOriginal - numberOfElementsLeft);
                j++) {
            temp += arrayToDecrease[j];
        }

        arrayToCopyResultTo[i] = temp / (float) usedInterval;

        numberOfElementsLeft -= usedInterval;
    }
    // compress zone B
    numberOfElementsLeft = numberOfElementsInOriginal * inclusionZonePercent;   
    for (i = (numberOfElementsInOriginal - numberOfElementsLeft);
            i < (numberOfDesiredElements + (numberOfDesiredElements % 2));
            i++) // i starts at the end of the board minus the appropriate percentile and fills array with half of desired point or halfwat + 1
    {
        usedInterval = numberOfElementsLeft /
                (((numberOfDesiredElements + (numberOfDesiredElements % 2)) / 2) - i);
        temp = 0;
        for (j = (numberOfElementsInOriginal - numberOfElementsLeft);
                j < (usedInterval + numberOfElementsInOriginal - numberOfElementsLeft);
                j++) {
            temp += arrayToDecrease[j];
        }

        arrayToCopyResultTo[i] = temp / (float)usedInterval;

        numberOfElementsLeft -= usedInterval;
    }
    return 1;
}

Я надеюсь, что этот алгоритм сможет взять начальный процентиль массива и конец, сжать значения (через усредняющие записи) и выводить значения в массиве, игнорируя средние значения массива.

1 Ответ

0 голосов
/ 06 февраля 2019

Как я писал в комментариях, у вас есть определенная ошибка в

numberOfElementsInOriginal = sizeof(arrayToDecrease);

, потому что sizeof(arrayToDecrease) дает вам размер указателя в байтах, который никоим образом не связан с числомэлементы в массиве (в), на которые указывает указатель.Поскольку numberOfElementsInOriginal является параметром функции, я склонен предположить, что это нежелательный остаток от предыдущей версии функции, поэтому его можно просто удалить.

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

  • ваш код может быть как укорочен, так и упрощен, если выделить его в отдельную функцию

, которую вы вызываете дважды.Кроме того, хотя я очень редко говорю это в SO-ответе,

  • имена ваших переменных слишком длинные.

Эти длинные имена довольно четкие, но стак много имен переменных такой большой длины делает ваш код труднее читать и понимать, а не легче, особенно когда некоторые из них похожи друг на друга.Вы можете создавать более короткие имена, которые все еще достаточно описательны, начиная с более коротких фраз, опуская предлоги, используя сокращения (особенно обычные), и даже просто выражая идею по-другому.Например,

plcbit arrayCompressFloatExtremities(float *dest,
        float *src, unsigned long dest_len,
        unsigned long src_len, float inclusion_fraction)

Я также переключился на snake_style вместо camelStyle.Первый более распространен в коде C, и я предпочитаю его в этом контексте, но последний тоже в порядке.

Что касается фактического усреднения, если у вас возникли проблемы с соблюдением кода, достаточного для уверенности в его правильноститогда правильность не является его глубокой проблемой.Я не знаю о вас, но даже зная (я думаю), что вы пытаетесь сделать, мне очень трудно проанализировать ваш код, чтобы проверить его.В дополнение к проблемам, о которых я уже упоминал, эта проблема частично возникает из-за использования

  • сложных встроенных выражений

, и особенно вопиюще, что

  • такие выражения дублируются и
  • некоторые являются ненужными сложными.

Возьмите это многократно повторяемое выражение вв частности:

numberOfDesiredElements - (numberOfDesiredElements % 2)) / 2

Учитывая, что numberOnumberOfDesiredElements имеет целочисленный тип без знака, это выражение будет всегда иметь тот же результат, что и просто

numberOfDesiredElements / 2

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

Рассмотрим эту альтернативу в форме функции, которую можно вызывать один раз для каждой половины:

/*
 * Partitions the source array evenly into dest_len bins, and records the average
 * of the elements in each bin in the corresponding element of the destination
 * array.  When dest_len does not evenly divide src_len, each of the src_len % dest_len
 * initial bins is one element longer than the trailing bins.
 *
 * dest:     a pointer to the array wherein the results are to be stored
 * dest_len: the number of leading elements of dest to fill; must not exceed src_len
 * src:      a pointer to the array containing the source elements
 * src_len:  the number of initial elements of src to process
 */
void compress_array(float *dest, size_t dest_len, float *src, size_t src_len) {
    // This implementation depends on these assumptions to be true:
    assert(0 < dest_len && dest_len <= src_len && dest_len <= ULONG_MAX / 2 + 1);

    size_t base_bin_size = src_len / dest_len;
    size_t num_extras = src_len % dest_len;

    // Iterate over the bins
    for (size_t dest_inx = 0; dest_inx < dest_len; dest_inx++) {
        // This is a concise (but perhaps too clever) way of distributing
        // the left-over source elements to bins, one element to each bin
        // until they are used up.  It depends on the fact that relational
        // expressions evaluate to either 0 or 1, and on the fact that
        // unsigned arithmetic wraps around:
        unsigned long bin_size = base_bin_size + (--num_extras < dest_len);

        // Average the elements in this bin
        float temp = 0;
        for (size_t bin_inx = 0; bin_inx < bin_size; bin_inx++) {
            // keeps track of our position in the source array by incrementing src
            temp += *(src++);
        }

        dest[dest_inx] = temp / bin_size;
    }
}

Для меня это просто и понятно, и оно четко выполняет ту работу, которую задокументировано.(И обратите внимание: то, что она делает, хорошо и четко задокументировано.) Я не уверен, что для выполнения этой функции задокументировано то, что вам нужно для выполнения этой функции, но суть в том, чтобы продемонстрировать некоторые способы написания более четких, более понятный код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...