在完全用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
是输出数组的长度,应为25unsigned long numberofElementsInOriginal
是原始数组的长度,> = 25float 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/