在完全用C语言编写的PLC上运行以下问题。该功能是我尝试添加的库的一部分。

我有一个任意长度的数据浮点数组。当数组长度大于等于25个条目时,将触发以下代码。该函数应该确定条目的前x个和最后x个百分比(即,数组99中的33%将是前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;
}


我希望该算法将能够获取数组的开始和结束的百分位数,压缩值(通过对条目进行平均),并在忽略数组的中间值的情况下在数组中输出值。

最佳答案

正如我在评论中所写,您在

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;
    }
}


对我来说,这很简单明了,并且显然可以完成它所记录的工作。 (并且请注意:它的作用是正确的,并且有明确的记录。)我不确定该函数所记录的功能正是您需要该函数执行的操作,但实际上是要演示一些更清晰地编写方法,更易于维护的代码。

关于c - 尝试取数组开始和结束的特定部分的平均值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54556811/

10-12 16:15
查看更多