Home AMX User Forum AMXForums Archive Threads Residential Forum

Finding total value of an array of numbers..

I am programming a security system and I have an integer array for all of the zones in which each array position or zone number will have a value of 0=closed or 1=open. How is the best way to take this data and have a system ready value that is =1 if all of the zones in the array are =0 and system ready value=0 if any position in the array is =1?
«1

Comments

  • Joe HebertJoe Hebert Posts: 2,159
    def90 wrote: »
    I am programming a security system and I have an integer array for all of the zones in which each array position or zone number will have a value of 0=closed or 1=open. How is the best way to take this data and have a system ready value that is =1 if all of the zones in the array are =0 and system ready value=0 if any position in the array is =1?
    How about something like this:
    DEFINE_FUNCTION INTEGER fnIsSystemReady() {
    
       INTEGER x
       
       FOR (x=1; x<=nNumberOfZones; x++) {
          IF (nZones[x] = 1) RETURN 0
       }
       RETURN 1
    }
    
    nSystemReady = fnIsSystemReady()
    
  • glr-ftiglr-fti Posts: 286
    along the same lines.....
    DEFAULT:
    {
    		    FOR(I=1;I<=nHAI_Max_zones;I++)		// max zones defined on this system 
    		    {
    			nSecMsgFlag=0				// set to 0 to send OK message unless a zone is not secure
    			IF(nSecPointState[I]=1)
    			{
    			    I=nHAI_Max_zones+1			// if any zone is not secure do not write out OK message
    			    nSecMsgFlag=1				// set flag
    			}
    		    }
    		    IF(nSecMsgFlag=0)
    		    {
    			SEND_COMMAND dvTP,"'^TXT-250,0,System OK'"
    		    }
    		}
    
    
  • def90def90 Posts: 14
    yeah, those are close to what I was thinking.. was hoping there was maybe a slightly simpler/quicker way as in maybe a keyword or mathematical formula of something..

    Thanks
  • kbeattyAMXkbeattyAMX Posts: 358
    def90 wrote: »
    yeah, those are close to what I was thinking.. was hoping there was maybe a slightly simpler/quicker way as in maybe a keyword or mathematical formula of something..

    Thanks

    This sounds like a great application for binary! Use bor and bxor to turn a bit on or off. One integer variable will give you 16 zones. The simply say if (!securityZones) then ready to arm. You could employ many ways to turn on and off the bits. I like using the shift operator. Let me know if you need more detail.
  • a_riot42a_riot42 Posts: 1,624
    def90 wrote: »
    I am programming a security system and I have an integer array for all of the zones in which each array position or zone number will have a value of 0=closed or 1=open. How is the best way to take this data and have a system ready value that is =1 if all of the zones in the array are =0 and system ready value=0 if any position in the array is =1?


    Why not use find_string? No for loop required.
    Paul
  • viningvining Posts: 4,368
    a_riot42 wrote:
    Why not use find_string? No for loop required
    I would assume the internal process of the find_string function is based on a for loop which uses length string and the specified starting index position to compare the find_string string to the variable string. This has to start at the starting index position and upon the first mismatch shift the starting index position and start all over again until it either makes it all the way through and gets a match or finds another mismatch in which case it has to shift it starting index again and start all over again. Its got to be one of the most laborious functions this language has so the simple for loop in my estimation would be the lesser of the two evils.

    Any way how would you use the find_string on an integer array?
  • a_riot42a_riot42 Posts: 1,624
    vining wrote: »
    a_riot42 wrote:

    I would assume the internal process of the find_string function is based on a for loop which uses length string and the specified starting index position to compare the find_string string to the variable string. This has to start at the starting index position and upon the first mismatch shift the starting index position and start all over again until it either makes it all the way through and gets a match or finds another mismatch in which case it has to shift it starting index again and start all over again. Its got to be one of the most laborious functions this language has so the simple for loop in my estimation would be the lesser of the two evils.

    I don't think I understand what you mean. If you use find_string to search for a 1, the first 1 it comes to will return and you are done.

    So if your array looks like this:

    array[] = {0,0,0,1,0,0,1,1,1,0,0,0}

    then find_string will start looking from the beginning, get to the fourth element and return. It won't continue to look for another 1 since it already found one. I think that is what the OP wanted, where if at least one element is 1, the variable is true or all are 0, the variable is false.

    The worst case is this:
    array[] = {0,0,0,0,0,0,0,0,0,0,0,1}

    where the 1 isn't found until the end, but the same would be true for a for loop search.

    A for loop will certainly work, but generally system commands execute more quickly as they have been optimized for the processor.
    vining wrote: »
    a_riot42 wrote:
    Any way how would you use the find_string on an integer array?

    That is left as an exercise for the reader :)
    Paul
  • viningvining Posts: 4,368
    a-riot42 wrote:
    If you use find_string to search for a 1, the first 1 it comes to will return and you are done.
    Ok, if you're looking for a single char then find_string is virtually the same as the for loop and assuming system functions are indeed optimized it may be more effecient. I'd be interested to see a side by side comparsion of the two methods.
    That is left as an exercise for the reader.
    Since I'm a little slower than most of you folks how's about an example.
  • a_riot42a_riot42 Posts: 1,624
    vining wrote: »
    a-riot42 wrote:
    Ok, if you're looking for a single char then find_string is virtually the same as the for loop and assuming system functions are indeed optimized it may be more effecient. I'd be interested to see a side by side comparsion of the two methods.

    Execution time is less important to me than just being able to write a line of simple code instead of a for loop for a test. I prefer to write:
    status = find_string (array, string, 1) 
    

    rather than:
    stack_var integer i
    
    status = 0
    
    for (i=1; i <= length_array(array); i++)
    {
      if (array[i])
      { 
        status = 1
        break
      }
    }
    

    I really have no idea which would be faster if there is a difference at all. But it just makes for cleaner code, so that's why I prefer to use it.
    Paul
  • viningvining Posts: 4,368
    a-riot42 wrote:
    Execution time is less important to me than just being able to write a line of simple code instead of a for loop for a test. I prefer to write:

    status = find_string (array, string, 1)
    
    I completely agree but I still want to see how you get that to work on an integer array. I can't think of a clean way of doing that using a find_string and the concept just hurts my brain. :)
  • a_riot42a_riot42 Posts: 1,624
    vining wrote: »
    the concept just hurts my brain. :)

    That's what thinking feels like :)
    Paul
  • HedbergHedberg Posts: 671
    vining wrote: »
    a-riot42 wrote:

    I completely agree but I still want to see how you get that to work on an integer array. I can't think of a clean way of doing that using a find_string and the concept just hurts my brain. :)

    Well, if you consider that in Netlinx a string is just an array of 8-bit integers (a short integer, I guess), it would seem that if you can search a string for a 0 or 1 that you might be able to do so with an integer array (array of 16 bit integers) as well. I tried it and the expected type error resulted. TYPE_CAST didn't allow it to compile, either. Sometimes you can use an integer in a function that expects a character variable (8 bit/short integer) and get it to work, but not in this case, it seems.

    Of course, because the array is being used to store no integer value larger than 255, a CHAR data type can be used instead of an INTEGER type. That should allow the find_string function to work correctly.

    For a while a couple years ago I was on a kick to use CHAR variables whenever I wanted a variable that would never exceed 255, but it seems to cause warnings and other annoyances so I abandoned that fetish. Might work just fine in this case, though.
  • kbeattyAMXkbeattyAMX Posts: 358
    def90 wrote: »
    I am programming a security system and I have an integer array for all of the zones in which each array position or zone number will have a value of 0=closed or 1=open. How is the best way to take this data and have a system ready value that is =1 if all of the zones in the array are =0 and system ready value=0 if any position in the array is =1?

    How many zones? This is great stuff for bitwise. Instead of using an integer array use a binary number of 1's and 0's. Use bor to turn on a bit and band to turn it off.

    Open Zone1
    $00 bor $01 = $01 turning on the LSB of the 8 bit value 00000000 is now 00000001
    Close Zone 1
    if $01 band $01 $01 bxor $01 = $00 turning off the LSB of the 8 bit value 00000001 is now 00000000

    So if all zones are closed then the value for binary value is 0. So if not zones then arm system. Just use a CHAR for 8 Zones or an INTEGER for 16 zones.
  • TurnipTruckTurnipTruck Posts: 1,485
    kbeattyAMX wrote: »
    How many zones? This is great stuff for bitwise. Instead of using an integer array use a binary number of 1's and 0's. Use bor to turn on a bit and band to turn it off.

    Open Zone1
    $00 bor $01 = $01 turning on the LSB of the 8 bit value 00000000 is now 00000001
    Close Zone 1
    if $01 band $01 $01 bxor $01 = $00 turning off the LSB of the 8 bit value 00000001 is now 00000000

    So if all zones are closed then the value for binary value is 0. So if not zones then arm system. Just use a CHAR for 8 Zones or an INTEGER for 16 zones.

    Listen to this guy with his binary methods. :) I have. Good stuff.
  • a_riot42a_riot42 Posts: 1,624
    kbeattyAMX wrote: »
    How many zones? This is great stuff for bitwise. Instead of using an integer array use a binary number of 1's and 0's. Use bor to turn on a bit and band to turn it off.

    Open Zone1
    $00 bor $01 = $01 turning on the LSB of the 8 bit value 00000000 is now 00000001
    Close Zone 1
    if $01 band $01 $01 bxor $01 = $00 turning off the LSB of the 8 bit value 00000001 is now 00000000

    So if all zones are closed then the value for binary value is 0. So if not zones then arm system. Just use a CHAR for 8 Zones or an INTEGER for 16 zones.

    What if you have hundreds of zones, like most security systems seem to have these days? Its better to use arrays than bits I would think. Easier to debug, that's for sure, and memory isn't really at a premium like it would be in an embedded device.
    Paul
  • TurnipTruckTurnipTruck Posts: 1,485
    a_riot42 wrote: »
    What if you have hundreds of zones, like most security systems seem to have these days? Its better to use arrays than bits I would think. Easier to debug, that's for sure, and memory isn't really at a premium like it would be in an embedded device.
    Paul

    Sure, memory really isn't an issue. However, like Ken, I am always in search or the slickest, least wordy ways of getting things done.
  • Spire_JeffSpire_Jeff Posts: 1,917
    vining wrote: »
    a-riot42 wrote:

    Ok, if you're looking for a single char then find_string is virtually the same as the for loop and assuming system functions are indeed optimized it may be more effecient. I'd be interested to see a side by side comparsion of the two methods.


    Since I'm a little slower than most of you folks how's about an example.

    Here is the side by side comparison:

    Line 59 (18:04:42.890):: *********************************************************
    Line 60 (18:04:42.890):: * TEST 1 REPORT: FIND_STRING 1000x
    Line 61 (18:04:42.890):: * Most recent 5 runs:
    Line 62 (18:04:42.906):: * 1: 13ms
    Line 63 (18:04:42.906):: * 2: 13ms
    Line 64 (18:04:42.906):: * 3: 0ms
    Line 65 (18:04:42.906):: * 4: 0ms
    Line 66 (18:04:42.906):: * 5: 0ms
    Line 67 (18:04:42.906):: *
    Line 68 (18:04:42.906):: * Average run time: 13ms - over 2 tests
    Line 69 (18:04:42.906):: *********************************************************
    Line 70 (18:04:42.906):: *********************************************************
    Line 71 (18:04:42.906):: * TEST 2 REPORT: FOR Loop 1000x
    Line 72 (18:04:42.906):: * Most recent 5 runs:
    Line 73 (18:04:42.906):: * 1: 810ms
    Line 74 (18:04:42.906):: * 2: 808ms
    Line 75 (18:04:42.906):: * 3: 0ms
    Line 76 (18:04:42.906):: * 4: 0ms
    Line 77 (18:04:42.906):: * 5: 0ms
    Line 78 (18:04:42.906):: *
    Line 79 (18:04:42.921):: * Average run time: 809ms - over 2 tests
    Line 80 (18:04:42.921):: *********************************************************

    Here is the code block tested:
    button_event[dvTp,202]{
    	push:{
    		stack_var integer x;
    		stack_var integer y;
    		stack_var char nArrayTest[100];
    		stack_var char sFindMe[10];
    		stack_var integer nTestResult;
    		
    		TestName(1,'FIND_STRING 1000x');
    		TestName(2,'FOR Loop 1000x');
    		sFindMe = "$01";
    		for(x=100;x;x--){
    			nArrayTest[x] = 0;
    		}
    		nArrayTest[50] = 1;
    		set_length_array(nArrayTest,100);
    		TestStart(1);
    		for(x=1000;x;x--)
    			nTestResult = 0;
    			nTestResult = find_string(nArrayTest,sFindMe,1);
    		TestFinish(1);
    		send_string 0,"'T1 Result is:',itoa(nTestResult)"
    		TestStart(2);
    		for(x=1000;x;x--){
    			nTestResult = 0
    			for(y=MAX_LENGTH_ARRAY(nArrayTest);y;y--)
    				if(nArrayTest[y]){
    					nTestResult = 1;
    					break;
    				}
    		}
    		TestFinish(2);
    		send_string 0,"'T2 Result is:',itoa(nTestResult)"
    		TestPrintReport(1);
    		TestPrintReport(2);
    	}
    }
    

    A couple of observations:
    - I had to switch to a char array as I could not get it to compile using an integer array.
    - I had to initialize the char array data to 0 because it was not done automatically.
    - I had to set the length of the array accordingly for find_string to work. (I think)


    Jeff
  • viningvining Posts: 4,368
    Wow, I never would have imagined that a for loop would take over 60x longer than find_string to perform the same task.

    Oh and when I said I was slow that was referring to getting find_string to work on an integer array but I guess if you're just tracking 1 & 0 for security zone states it's easy enough to just put them in a char array as chars in what ever size string you need to cover your zones.
  • a_riot42a_riot42 Posts: 1,624
    That isn't really a fair test because you calling max_length_array 1000 times as well. This could be rewritten as

    bFaultState = 0
    length = max_length_array(nArrayTest)

    for(x=1000;x;x--)
    {
    for (bFaultState = length; bFaultState && !nArrayTest[bFaultState]; bFaultState--);
    print("'Faulted at ', itoa(bFaultState)) // zero is no faults
    }

    I wonder if it would be any faster in your test program against find_string.
    Paul
  • Spire_JeffSpire_Jeff Posts: 1,917
    a_riot42 wrote: »
    That isn't really a fair test because you calling max_length_array 1000 times as well. This could be rewritten as

    bFaultState = 0
    length = max_length_array(nArrayTest)

    for(x=1000;x;x--)
    {
    for (bFaultState = length; bFaultState && !nArrayTest[bFaultState]; bFaultState--);
    print("'Faulted at ', itoa(bFaultState)) // zero is no faults
    }

    I wonder if it would be any faster in your test program against find_string.
    Paul
    I will check it out in the morning. I originally left in the max_length_array because I wanted to test everything that is required, but as you pointed out, I did not follow the same philosophy on the find_string section.

    Jeff
  • Spire_JeffSpire_Jeff Posts: 1,917
    Ok, I plugged in the following code change and it slowed down!
    		nLength = MAX_LENGTH_ARRAY(nArrayTest)
    		TestStart(2);
    		for(x=1000;x;x--){
    			nTestResult = 0
    			for(y=nLength;y && !nArrayTest[y];y--);
    			nTestResult = y;
    		}
    		TestFinish(2);
    

    Here is the new time information:

    Line 20 (08:44:50.875):: * TEST 1 REPORT: FIND_STRING 1000x
    Line 21 (08:44:50.890):: * Most recent 5 runs:
    Line 22 (08:44:50.890):: * 1: 14ms
    Line 23 (08:44:50.890):: * 2: 12ms
    Line 24 (08:44:50.890):: * 3: 13ms
    Line 25 (08:44:50.890):: * 4: 0ms
    Line 26 (08:44:50.890):: * 5: 0ms
    Line 27 (08:44:50.890):: *
    Line 28 (08:44:50.890):: * Average run time: 13ms - over 3 tests
    Line 29 (08:44:50.890):: *********************************************************
    Line 30 (08:44:50.890):: *********************************************************
    Line 31 (08:44:50.890):: * TEST 2 REPORT: FOR Loop 1000x
    Line 32 (08:44:50.890):: * Most recent 5 runs:
    Line 33 (08:44:50.890):: * 1: 911ms
    Line 34 (08:44:50.890):: * 2: 909ms
    Line 35 (08:44:50.890):: * 3: 909ms
    Line 36 (08:44:50.890):: * 4: 0ms
    Line 37 (08:44:50.906):: * 5: 0ms
    Line 38 (08:44:50.906):: *
    Line 39 (08:44:50.906):: * Average run time: 909ms - over 3 tests
    Line 40 (08:44:50.906):: *********************************************************

    I just switched it back to the way I had it, but pulling the MAX_LENGTH_ARRAY out of the 1000x loop. The average time this way was 780ms.

    Jeff
  • a_riot42a_riot42 Posts: 1,624
    Spire_Jeff wrote: »

    I just switched it back to the way I had it, but pulling the MAX_LENGTH_ARRAY out of the 1000x loop. The average time this way was 780ms.

    Jeff

    Interesting. Looks like find_string wins with flying colors no?
    Paul
  • Spire_JeffSpire_Jeff Posts: 1,917
    As far as speed goes, yes it does win. One just has to pay a little more attention to some details such as set_array_length and type_cast when necessary.

    Jeff
  • a_riot42a_riot42 Posts: 1,624
    Spire_Jeff wrote: »
    As far as speed goes, yes it does win. One just has to pay a little more attention to some details such as set_array_length and type_cast when necessary.

    Jeff

    Oh? I don't recall using type_cast or set_array_length. Where are you using them?
    Paul
  • Spire_JeffSpire_Jeff Posts: 1,917
    I didn't have to use the type_cast here, but I think if you are trying to assign an integer to the char array, you will have to type_cast (since it may lose data). As for the set_length_array, I had to use it before I ran the find_string. This might be necessary because I am using stack_vars for the test. The thing with this is that no errors are generated, it just doesn't find the string because it doesn't think there is anything in the array. In this limited test, it was easy to figure out, but in a real programming job it could cause an hour or two of staring at the screen :)

    Jeff
  • viningvining Posts: 4,368
    Why the double loops?
    nLength = MAX_LENGTH_ARRAY(nArrayTest)
    TestStart(2);
    for(x=1000;x;x--)
         {
         nTestResult = 0
         for(y=nLength;y && !nArrayTest[y];y--);
         nTestResult = y;
         }
    TestFinish(2);
    
    Shouldn't it just be the single loop? Aren't you running the 2nd loop 1000 times?
    nLength = MAX_LENGTH_ARRAY(nArrayTest)
    TestStart(2);
    nTestResult = 0
    
    for(y=nLength;y && !nArrayTest[y];y--);//does this just keep the loop on itself???
         {//                              ^
         //braces aren't needed if semi colon returns the loop to itself, never tried it.
         }
    nTestResult = y;
     
    TestFinish(2);
    
    assuming the arrays are all 0's.
  • Spire_JeffSpire_Jeff Posts: 1,917
    vining wrote: »
    Why the double loops?
    Shouldn't it just be the single loop? Aren't you running the 2nd loop 1000 times?
    The main loop is there to simply execute the code 1000x. Think of it like looking at the execution through a microscope. I run both tests 1000 times each. I use the same repetition code for each test so that any overhead introduced by the looping code should be the same in each test. By doing the test 1000 times, I hope to reduce the effect of odd anomalies on the final result. I then run the test multiple times to again reduce the effect of anomalies and take the average. On something as fast to execute as the tests we are talking about, they happen too quickly to be measured accurately in code. Timelines give me the best resolution at .001 seconds, but sometimes the execution would be so fast with a single iteration that it could show up as .001 seconds and actually only take .00001 seconds. If you compared this to something that takes .002 seconds, the results appear very different. (.001 vs .002 = 1/2 the time, .00001 vs .002 = 1/200 the time. or 2x faster vs 200x faster :) )
    vining wrote: »
    nLength = MAX_LENGTH_ARRAY(nArrayTest)
    TestStart(2);
    nTestResult = 0
    
    for(y=nLength;y && !nArrayTest[y];y--);//does this just keep the loop on itself???
         {//                              ^
         //braces aren't needed if semi colon returns the loop to itself, never tried it.
         }
    nTestResult = y;
     
    TestFinish(2);
    
    assuming the arrays are all 0's.
    Yes, it does just loop on itself. I also added the brackets just to verify this, but did not see a change in times. Actually, if the array has a non-zero value in it, it will speed up execution time because it will stop as soon as it finds a non-zero value.

    Jeff
  • Spire_JeffSpire_Jeff Posts: 1,917
    To illustrate the variable nature of the timing involved in the for loop method, I ran the test a couple of times but I changed the place where the 1 is inserted in the array. You can see that the times of the for loop varied greatly based on the position in the array. The interesting thing is that the was almost no fluctuation in the find_string method.

    Results:

    Line 379 (14:14:13.062):: *********************************************************
    Line 380 (14:14:13.062):: * TEST 1 REPORT: FIND_STRING 1000x
    Line 381 (14:14:13.062):: * Most recent 5 runs:
    Line 382 (14:14:13.062):: * 1: 13ms
    Line 383 (14:14:13.062):: * 2: 13ms
    Line 384 (14:14:13.062):: * 3: 13ms
    Line 385 (14:14:13.078):: * 4: 13ms
    Line 386 (14:14:13.078):: * 5: 13ms
    Line 387 (14:14:13.078):: *
    Line 388 (14:14:13.078):: * Average run time: 12ms - over 10 tests
    Line 389 (14:14:13.078):: *********************************************************
    Line 390 (14:14:13.078):: *********************************************************
    Line 391 (14:14:13.078):: * TEST 2 REPORT: FOR Loop 1000x
    Line 392 (14:14:13.078):: * Most recent 5 runs:
    Line 393 (14:14:13.078):: * 1: 1251ms
    Line 394 (14:14:13.078):: * 2: 1196ms
    Line 395 (14:14:13.078):: * 3: 1654ms
    Line 396 (14:14:13.078):: * 4: 1533ms
    Line 397 (14:14:13.078):: * 5: 1566ms
    Line 398 (14:14:13.078):: *
    Line 399 (14:14:13.078):: * Average run time: 1431ms - over 10 tests
    Line 400 (14:14:13.078):: *********************************************************


    Jeff

    P.S.
    all of the insertion points happened to be in the lower positions (I think they ranged from 5 to 40). Had an insertion point gone above 50, you would see a faster time.
  • a_riot42a_riot42 Posts: 1,624
    Wow, two orders of magnitude faster using find_string. Thanks for running the tests.
    Paul
  • HedbergHedberg Posts: 671
    Spire_Jeff wrote: »
    I didn't have to use the type_cast here, but I think if you are trying to assign an integer to the char array, you will have to type_cast (since it may lose data). As for the set_length_array, I had to use it before I ran the find_string. This might be necessary because I am using stack_vars for the test. The thing with this is that no errors are generated, it just doesn't find the string because it doesn't think there is anything in the array. In this limited test, it was easy to figure out, but in a real programming job it could cause an hour or two of staring at the screen :)

    Jeff

    I've been thinking about array length with respect to this problem and was wondering if making the array one element longer than necessary and then inserting a bogus number in the last element would solve the problem. For example, if you actually had 8 zones, could you write:
    char sArrayofZones[] = {0,0,0,0,0,0,0,0,200}
    

    As long as the find_string function is only looking for zero and one and you remember to not test the extra element, wouldn't it work?
Sign In or Register to comment.