以下问题正在完全用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;
}
我希望该算法将能够获取数组的开头和结尾的百分位数,压缩值(通过对条目进行平均),并在数组中输出值,而忽略数组的中间值。
答案 0 :(得分:0)
正如我在评论中所写,您的确存在错误
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;
}
}
对我来说,这很简单明了,并且显然可以完成所记录的工作。 (并且请注意:它的作用是正确且清楚地记录在案。)我不确定文件所记录的工作正是您需要该函数执行的工作,但重点实际上是演示一些更清晰地编写方法,更易于维护的代码。