Go Down

### Topic: square of small int displays as negative number?? (Read 140 times)previous topic - next topic

#### paynterf ##### Nov 09, 2018, 03:56 am
I have a small program to calculate the incremental variance of a series of small (less than 255) integers acquired from a LIDAR unit.  The calculation involves squaring the distance values and then dividing them by the number of distances considered.  This works fine, except occasionally I get a negative number reported by Serial.println() for dist * dist.  This obviously cannot be true, but I cannot figure out what I'm doing wrong.  I've included the code below, along with a sample printout.  I've seen both the 'olddist_squared' and 'newdist_squared' values reported as negative numbers.

NOTE:  I had to include the printout as an attachment to get under the 9000 character limit.  In the attachment, search for 'olddist_squared = -26332.00', 'olddist_squared = -29436.00' and 'newdist_squared = -30567.00'

TIA,

Frank

Code: [Select]
`/*    Name:       PrintExTest.ino    Created: 11/5/2018 8:03:18 AM    Author:     FRANKWIN10\Frank*/#include <elapsedMillis/elapsedMillis.h>#include <PrintEx.h>StreamEx mySerial = Serial;const int DIST_ARRAY_SIZE = 5;byte aFrontDist[DIST_ARRAY_SIZE];int bitbucket_dist = 0; //the oldest distanceelapsedMillis sinceLastNavUpdateMsec; //added 10/15/18 to replace lastmillisecdouble last_incvar = 0;double last_incmean = 0;const int MIN_PING_INTERVAL_MSEC = 200; //rev 03/12/16void setup(){ Serial.begin(115200); //04/01/15 initialize distance array for (int i = 0; i < DIST_ARRAY_SIZE; i++) { aFrontDist[i] = random(10, 200); } //04/01/15 display initial distance array contents for (int i = 0; i < DIST_ARRAY_SIZE; i++) { mySerial.printf("aFrontDist[%d] = %d\n",i, aFrontDist[i]); } //calc mean long sum = 0; for (int i = 0; i < DIST_ARRAY_SIZE; i++) { sum += aFrontDist[i]; //adds in rest of values } float brute_mean = (float)sum / (float)DIST_ARRAY_SIZE; Serial.print("sum = "); Serial.print(sum); Serial.print(", mean = "); Serial.println(brute_mean); // Step2: Sum up squared deviation of each array item from mean float sumsquares = 0; for (int i = 0; i < DIST_ARRAY_SIZE; i++) { sumsquares += (aFrontDist[i] - brute_mean)*(aFrontDist[i] - brute_mean); } // Step3: Divide squared deviation sum by number of array elements double brute_var = sumsquares / DIST_ARRAY_SIZE; Serial.print("sumquares/brute mean/var: "); Serial.print(sumsquares); Serial.print("/"); Serial.print(brute_mean); Serial.print("/"); Serial.println(brute_var); sinceLastNavUpdateMsec = 0; //added 10/15/18}void loop(){ if (sinceLastNavUpdateMsec >= MIN_PING_INTERVAL_MSEC) { sinceLastNavUpdateMsec -= MIN_PING_INTERVAL_MSEC; int newDistVal = random(0, 200); CalcDistArrayVariance(newDistVal, aFrontDist); }}double  CalcDistArrayVariance(int newdistval, byte* aDistArray){ //Purpose:  Calculate Variance of input array //Inputs: aDistArray = DIST_ARRAY_SIZE array of integers representing left/right/front distances //Outputs: Variance of selected array //Plan: // Step1: Calculate mean for array // Step2: Sum up squared deviation of each array item from mean // Step3: Divide squared deviation sum by number of array elements //Notes: // 11/01/18 this function takes about 1.8mSec - small compared to 200mSec loop interval // 11/02/18 added distval to sig to facilitate incremental calc algorithm//DEBUG!! mySerial.printf("CalcDistArrayVariance(%d) called\n", newdistval); //for (int i = 0; i < DIST_ARRAY_SIZE; i++) //{ // mySerial.printf("%d\t%d\n", i, aFrontDist[i]); //} //DEBUG!! long funcStartMicrosec = micros(); //11/03/18 update distance array, saving oldest for later use in incremental calcs //int oldestDistVal = aFrontDist; //calc mean long sum = 0; for (int i = 0; i < DIST_ARRAY_SIZE; i++) { //aFrontDist[i] = aFrontDist[i + 1]; sum += aDistArray[i]; //adds in rest of values } float brute_mean = (float)sum / (float)DIST_ARRAY_SIZE; Serial.print("sum = "); Serial.print(sum); Serial.print(", mean = "); Serial.println(brute_mean); // Step2: Sum up squared deviation of each array item from mean float sumsquares = 0; for (int i = 0; i < DIST_ARRAY_SIZE; i++) { sumsquares += (aDistArray[i] - brute_mean)*(aDistArray[i] - brute_mean); } // Step3: Divide squared deviation sum by number of array elements double brute_var = sumsquares / DIST_ARRAY_SIZE; Serial.print("sumquares/brute mean/var: "); Serial.print(sumsquares); Serial.print("/"); Serial.print(brute_mean); Serial.print("/"); Serial.println(brute_var); last_incmean = brute_mean; last_incvar = brute_var; //11/02/18 now re-do the calculation using the incremental method, and compare the times //mu_t = mu_(t-1) - dist_(t-N)/N + dist_t/N //mu_7 = mu_(6) - dist_(2)/N + dist_7/N //var^2_t = var^2_(t-1) + dist^2_(t) - dist^2_(t-N) + mu^2_(t-1) - mu^2_t //var^2_7 = var^2_(6) + dist^2_(7) - dist^2_(t-N) + mu^2_(6) - mu^2_7 //11/03/18 update distance array, saving oldest for later use in incremental calcs int oldestDistVal = aFrontDist; //shift all frontdist values down one (the 0th value drops into the bit bucket) //combine this with mean calc sum = 0; for (int i = 0; i < DIST_ARRAY_SIZE; i++) { aFrontDist[i] = aFrontDist[i + 1]; } aFrontDist[DIST_ARRAY_SIZE - 1] = newdistval; for (int i = 0; i < DIST_ARRAY_SIZE; i++) { Serial.print("aDistArray["); Serial.print(i); Serial.print("] = "); Serial.println(aDistArray[i]); } mySerial.printf("olddist, newdist: %d, %d\n", oldestDistVal, newdistval); Serial.print("last_incmean, last_incvar "); Serial.print(last_incmean); Serial.print(", "); Serial.println(last_incvar); double inc_mean = last_incmean - oldestDistVal / DIST_ARRAY_SIZE + newdistval / DIST_ARRAY_SIZE; Serial.print("newdist = "); Serial.println(newdistval); Serial.print("olddist = "); Serial.println(oldestDistVal); double olddist_squared = oldestDistVal * oldestDistVal; double newdist_squared = newdistval * newdistval; Serial.print("olddist_squared = "); Serial.println(olddist_squared); Serial.print("newdist_squared = "); Serial.println(newdist_squared); Serial.print("last_inc_var = "); Serial.println(last_incvar); Serial.print("newdistval*newdistval / DIST_ARRAY_SIZE = "); Serial.println(newdist_squared / DIST_ARRAY_SIZE); Serial.print("oldestDistVal*oldestDistVal / DIST_ARRAY_SIZE = "); Serial.println(olddist_squared / DIST_ARRAY_SIZE); Serial.print("last_inc_mean = "); Serial.println(last_incmean); Serial.print("inc_mean = "); Serial.println(inc_mean); double inc_var = last_incvar + (newdist_squared / DIST_ARRAY_SIZE) - (olddist_squared / DIST_ARRAY_SIZE) + last_incmean * last_incmean - inc_mean * inc_mean; last_incvar = inc_var; //save for next time last_incmean = inc_mean; //save for next time //long inc_varDur = micros() - funcStartMicrosec - brute_varDur; //display results: Serial.print("inc_mean/inc_var:"); Serial.print(inc_mean); Serial.print("/");Serial.println(inc_var);}`

#### jremington #1
##### Nov 09, 2018, 04:05 amLast Edit: Nov 09, 2018, 04:07 am by jremington
The largest positive value for a "signed int" (default) variable is 32767, the square root of which is 181.

Overflow tends to result in negative values, so use long int instead.

#### paynterf #2
##### Nov 09, 2018, 04:09 pm
Yeah, that was the problem - I was thinking 65,536, but of course that's for UNSIGNED int.  Sorry to bother y'all ;-)

Regards,

Frank

Go Up