diff --git a/MMS24-25.c b/MMS24-25.c index ece8c59..118ec30 100644 --- a/MMS24-25.c +++ b/MMS24-25.c @@ -161,7 +161,7 @@ ssize_t getline(char **lineptr, size_t *n, FILE *stream) { *pos = '\0'; -#ifdef _DEBUG_ +#ifdef _DEBUG _debug("getline: Read line '%s' with length %ld.", *lineptr, (pos - *lineptr)); #endif @@ -195,7 +195,7 @@ double interpolateLine( (dXq - dX1) / (dX2 - dX1) ); -#ifdef _DEBUG_ +#ifdef _DEBUG // DEBUG: print the parameters and result _debug("interpolateLine(%lf, %lf, %lf, %lf, %lf) -> %lf", dX1,dY1,dX2,dY2,dXq,y); @@ -237,7 +237,7 @@ void rescaleDoubleArray( // Calculate the offset double dOffset = dMin - dOldMin; -#ifdef _DEBUG_ +#ifdef _DEBUG _debug("rescaleDoubleArray: dOldMin = %lf", dOldMin); _debug("rescaleDoubleArray: dOffset = %lf", dOffset); #endif @@ -475,6 +475,9 @@ MMSignal *createSignalFromSignal(MMSignal *pmmsIn) { signal->pdValues[i] = pmmsIn->pdValues[i]; } } else { + if (pmmsIn->iNumValues != 0) + _error("createSignalFromSignal: pmmsIn->pdValues is NULL while pmmsIn->iNumValues is not %d", pmmsIn->iNumValues); + _warn("createSignalFromSignal: pmmsIn->pdValues is NULL"); signal->pdValues = NULL; } @@ -667,6 +670,21 @@ double calculateStddev(double *pdIn, int iLen) { return sqrt(stdDev / iLen); } +/* + * Compares two double values for the qsort function. + */ +int compareDoubles(const void* a, const void* b) { + int val_a = * ( (double*) a ); + int val_b = * ( (double*) b ); + + if ( val_a == val_b ) + return 0; + else if ( val_a < val_b ) + return -1; + else + return 1; +} + /* * Calculates the median of an array of double values `pdIn` of length `iLen`. * The median is calculated as the middle value of the sorted array if the @@ -679,11 +697,28 @@ double calculateMedian(double *pdIn, int iLen) { * \frac{pdIn_{\frac{|pdIn|}{2}} + pdIn_{\frac{|pdIn|}{2}+1}}{2} & \text{if } |pdIn| \text{ is odd} * \end{cases} \] */ + double *pdInSorted = NULL; + pdInSorted = (double*) malloc(sizeof(double) *iLen); + + if (iLen == 0) { + _warn("calculateMedian: iLen is 0"); + return 0; + } + + if (pdInSorted == NULL) + _mem_error("calculateMedian: Failed to allocate memory for pdInSorted"); + + for (int i = 0; i < iLen; i++) { + pdInSorted[i] = pdIn[i]; + } + + // Sort the array using stdlib's qsort function + qsort(pdInSorted, iLen, sizeof(double), compareDoubles); if (iLen % 2 == 0) { - return pdIn[iLen/2]; + return (pdIn[iLen/2 - 1] + pdIn[iLen/2]) / 2; } else { - return (pdIn[iLen/2] + pdIn[iLen/2+1]) / 2; + return pdIn[iLen/2]; } } @@ -707,9 +742,14 @@ LocalExtrema *initLocalExtrema(int *piInPos, int iLen) { return localExtrema; } -int getMinMaxPos(double *pdIn, int iLen, int *iMinPos, int *iMaxPos) { - *iMaxPos = 0; - *iMinPos = 0; +void getMinMaxPos(double *pdIn, int iLen, int *iMinPos, int *iMaxPos) { + *iMaxPos = -1; + *iMinPos = -1; + + if (iLen == 0) { + _warn("getMinMaxPos: iLen is 0"); + return; + } for (int i = 1; i < iLen; i++) { if (pdIn[i] > pdIn[*iMaxPos]) @@ -739,6 +779,10 @@ void findLocalExtremaFromArray( if (pdIn[i] > pdIn[i-1] && pdIn[i] > pdIn[i+1]) { iNumLocalMax++; +#ifdef _DEBUG + _debug("findLocalExtremaFromArray: Found local maximum at (%d, %lf)", i, pdIn[i]); +#endif + if (piLocalMaxPos == NULL) piLocalMaxPos = (int*) malloc(sizeof(int) *iNumLocalMax); else @@ -753,6 +797,10 @@ void findLocalExtremaFromArray( if (pdIn[i] < pdIn[i-1] && pdIn[i] < pdIn[i+1]) { iNumLocalMin++; +#ifdef _DEBUG + _debug("findLocalExtremaFromArray: Found local minimum at (%d, %lf)", i, pdIn[i]); +#endif + if (piLocalMinPos == NULL) piLocalMinPos = (int*) malloc(sizeof(int) *iNumLocalMin); else @@ -765,6 +813,11 @@ void findLocalExtremaFromArray( } } +#ifdef _DEBUG + _debug("findLocalExtremaFromArray: Found %d local maxima", iNumLocalMax); + _debug("findLocalExtremaFromArray: Found %d local minima", iNumLocalMin); +#endif + *ppexLocalMax = initLocalExtrema(piLocalMaxPos, iNumLocalMax); *ppexLocalMin = initLocalExtrema(piLocalMinPos, iNumLocalMin); } @@ -782,6 +835,13 @@ Extrema *initExtrema(double *pdIn, int iLen) { // Get the global extrema getMinMaxPos(pdIn, iLen, &extrema->iGlobalMinPos, &extrema->iGlobalMaxPos); +#ifdef _DEBUG + if (iLen > 0) { + _debug("initExtrema: Found global minimum at (%d, %lf)", extrema->iGlobalMinPos, pdIn[extrema->iGlobalMinPos]); + _debug("initExtrema: Found global maximum at (%d, %lf)", extrema->iGlobalMaxPos, pdIn[extrema->iGlobalMaxPos]); + } +#endif + // Initialize the local extrema extrema->pexLocalMax = NULL; extrema->pexLocalMin = NULL; @@ -831,7 +891,7 @@ Histogram *initHistogram(double *pdIn, int iLen, int iNumBins) { histogram->dIntervalMax = pdIn[i]; } -#ifdef _DEBUG_ +#ifdef _DEBUG _debug("initHistogram: histogram->dIntervalMin = %lf", histogram->dIntervalMin); _debug("initHistogram: histogram->dIntervalMax = %lf", histogram->dIntervalMax); #endif @@ -839,7 +899,7 @@ Histogram *initHistogram(double *pdIn, int iLen, int iNumBins) { histogram->dBinWidth = (histogram->dIntervalMax - histogram->dIntervalMin) / iNumBins; histogram->iNumBins = iNumBins; -#ifdef _DEBUG_ +#ifdef _DEBUG _debug("initHistogram: histogram->dBinWidth = %lf", histogram->dBinWidth); #endif @@ -866,7 +926,7 @@ Histogram *initHistogram(double *pdIn, int iLen, int iNumBins) { histogram->pdBinValues[i] /= iLen; } -#ifdef _DEBUG_ +#ifdef _DEBUG // DEBUG: print the parameters and result _debug("initHistogram(%lf, %lf, %lf, %d)", histogram->dIntervalMin,histogram->dIntervalMax,histogram->dBinWidth,histogram->iNumBins); @@ -914,6 +974,8 @@ double calculateEntropy(Histogram *phisIn) { /* * Convolve two signals `pmmsInA` and `pmmsInB` and return the result. + * Actually this should be named `convolveSignals` but the task specifies + * `convoluteSignals`. */ MMSignal *convoluteSignals(MMSignal *pmmsInA, MMSignal *pmmsInB) { // Calculate output length diff --git a/Makefile b/Makefile index 027277a..1c4b516 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC=gcc SOURCE_FILE=MMS24-25.c -OPTS=-lm -std=c99 +OPTS=-lm -std=c99 -D _DEBUG_ all: clean tests run diff --git a/tests.c b/tests.c index 6e5d9ca..83cddda 100644 --- a/tests.c +++ b/tests.c @@ -289,10 +289,18 @@ void testCalculateMedian() { double dMedian = calculateMedian(pdValues, 10); - if (dMedian != 6) { + if (dMedian != 5.5) { error("Failed to calculate the correct median: %lf != 5.5", dMedian); } + double pdValues2[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + + dMedian = calculateMedian(pdValues2, 9); + + if (dMedian != 5) { + error("Failed to calculate the correct median: %lf != 5", dMedian); + } + success("testCalculateMedian"); } @@ -385,6 +393,17 @@ void testGetPascalLine() { success("testGetPascalLine"); } +void testApplyPascalConvForSeriesGT40() { + info("testApplyPascalForSeriesGT40"); + + MMSignal *signal = getPascalLine(40); + MMSignal *signal2 = convoluteSignals(signal, signal); + + writeMMSignal("testApplyPascalForSeriesGT40.results.txt", signal2); + + success("testApplyPascalForSeriesGT40"); +} + void testComputeDFT() { info("testComputeDFT"); @@ -443,6 +462,40 @@ void testConvertPolar2Cart() { success("testConvertPolar2Cart"); } +void testCalcExtrema() { + info("testCalcExtrema"); + + double pdValues[] = {1, 2, 1, 0, -1, -2, -1, 0, 1, 5}; + + Extrema *extrema = initExtrema(pdValues, 10); + + if (extrema->pexLocalMax->iNumLocalExtrema != 1) { + error("Failed to calculate the correct number of local maxima: %d != 1", extrema->pexLocalMax->iNumLocalExtrema); + } + + if (extrema->pexLocalMin->iNumLocalExtrema != 1) { + error("Failed to calculate the correct number of local minima: %d != 1", extrema->pexLocalMin->iNumLocalExtrema); + } + + if (extrema->iGlobalMaxPos != 9) { + error("Failed to calculate the correct global maximum position: %d != 9", extrema->iGlobalMaxPos); + } + + if (extrema->iGlobalMinPos != 5) { + error("Failed to calculate the correct global minimum position: %d != 4", extrema->iGlobalMinPos); + } + + if (extrema->pexLocalMax->piLocalExtremaPos[0] != 1) { + error("Failed to calculate the correct local maximum position: %d != 9", extrema->pexLocalMax->piLocalExtremaPos[0]); + } + + if (extrema->pexLocalMin->piLocalExtremaPos[0] != 5) { + error("Failed to calculate the correct local minimum position: %d != 4", extrema->pexLocalMin->piLocalExtremaPos[0]); + } + + success("testCalcExtrema"); +} + int main (int iArgC, char** ppcArgV){ testInterpolation(); testSineAndReadWriteDoubleArray(); @@ -460,6 +513,8 @@ int main (int iArgC, char** ppcArgV){ testComputeDFT(); testConvertCart2Polar(); testConvertPolar2Cart(); + testApplyPascalConvForSeriesGT40(); + testCalcExtrema(); return 0; }