c - 尝试取数组开头和结尾特定部分的平均值

标签 c arrays compression

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

我有一个任意长度的 float 据数组。当数组长度 >= 25 条目时,将触发以下代码。该函数应该确定第一个和最后 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
  • floatclusionZonePercent是我要压缩的数组前后端的百分比。例如。输入 0.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 是一个函数参数,因此我倾向于猜测这是该函数的先前版本中不需要的剩余内容,因此可以简单地将其删除。

就样式和方法而言,您似乎对目标数组的前半部分使用了与后半部分完全相同的方法。如果这确实是您想要的,那么

  • 通过将其分解为单独的函数,可以缩短和简化您的代码

你打了两次电话。另外,虽然我很少在如此回答中这么说,

  • 您的变量名称太长。

这些长名称非常清晰,但是拥有如此多的如此长的变量名称会使您的代码更难阅读和理解,而不是更容易,特别是当其中几个彼此相似时。您可以通过从较短的短语开始、省略介词、使用缩写(尤其是常规缩写),甚至只是以不同的方式表达想法,来创建仍然具有充足描述性的较短名称。例如,

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/

相关文章:

C 没那么难 : void ( *( *f[] ) () ) ()

c++ - 如何从动态库中调用未知函数?

java - 如何区分父类(super class)数组中的不同子类?

php - 对 CSS、Javascript 等文件进行 gzip 一次并将其保存以供客户端使用的方法,而不是每次发出请求时都进行处理和 gzip 压缩

c++ - 快速信息集或 .net 二进制压缩开源库

c - 我的 C 代码有什么问题(由于 malloc,我的输出不稳定)?

c++ - 在运行时根据 CUDA 计算能力切换主机功能

javascript - 某些函数中的 JS/JQuery 全局数组错误

java - 在Java中单行打印数组

android获取zip文件中文件的压缩大小