isolating a digit

I’m trying to efficiently isolate a digit. For example If have two values x=1106 and y = 1000, I’m looking the compare the differences in a granular way by place value like so

tens place x is what to y tens place
what == equal
ones place x is what to y ones place
what == grater by 6

This post will become ridiculous fast if I explain the why portion of the problem.
Needless to say the part I’m having a hard time with is isolating the digits to make the comparisons.
Paying more attention in high school math probably would have helped me here…
anyhow, here is what I looked at as a possible example http://www.daniweb.com/software-development/cpp/threads/151273/integer-place-values
and here is where i’m at with test code.

#include<avr/pgmspace.h>

prog_uint16_t preDefLayout[28] PROGMEM=
//just a bunch of unsigned ints 
{
  1100,23000,2300,21000,1000,30000,3100,20001,32000,1500,3002,3000,6600,53000,
  60000,11000,15000,6000,3200,10,600,45000,20003,33000,62000,1001,1,10000
};

void setup()
{
  Serial.begin(9600);
  for(int i=0;i<28;i++)
  {
    unsigned int num = pgm_read_word_near(preDefLayout +i);
    for (int d=0; d<5; d++)
    {
      unsigned int num= compare%(10^d);
      unsigned int digit = a/(10^(d-1));
      Serial.print(" ");
      Serial.print(digit);
    }
    Serial.println();
  }
}

void loop()
{
}

From the context I guess you expect 10^d to represent ten to the power d. Unfortunately ^ is the bitwise exclusive OR operator so is not going to do what you want. You could use pow() if you're determined to use this approach. However, it seems to me like a very strange algorithm and I can't imagine any problem that this approach is a sensible solution to.

Hi, beware of redefining the num variable within the for block:

    unsigned int num = pgm_read_word_near(preDefLayout +i);
    for (int d=0; d<5; d++)
    {
      unsigned int num= compare%(10^d);

My approach would be: get the highest power of 10 less than the numbers to compare, take the leftmost digits from the numbers using division, compare them, discard the leftmost digit using the modulus operation, get the next lower power of 10, repeat the cycle.

This results in making the comparison from left to right, as in your requirement.

  unsigned long first_number_to_compare, second_number_to_compare;
// here assign some value to the numbers

  unsigned long max_number_to_compare = 
        first_number_to_compare > second_number_to_compare ?
                first_number_to_compare : second_number_to_compare;

// get the highest power of 10 that is less than the highest number
  unsigned long magnitude = 1;
  while (magnitude * 10 < max_number_to_compare)
  {
    magnitude *= 10;
  }

// compare the numbers starting from the leftmost digit
  while (magnitude > 0)
  {
    int first_digit_to_compare = first_number_to_compare / magnitude;
    int second_digit_to_compare = second_number_to_compare / magnitude;
// here compare the digits, print something

// cut off the leftmost digit
    first_number_to_compare %= magnitude;
    second_number_to_compare %= magnitude;
    magnitude /= 10;
}

it seems to me like a very strange algorithm and I can't imagine any problem that this approach is a sensible solution to

Peter,
honestly it looked like gibberish to me too, I just trusted the person knew what they were doing, but I guess with my copy and paste methodology its a prime way to give a foolish example.

I found another example here number place value - C++ Forum I'm just not sure how I can translate it to my problem.

spatula,
I'm still working out your solution in my head (l'm a bit of a dunce with math) having a hard time visualizing how the modulus operation cuts off the leftmost digit.

The modulus operator gives you the remainder when you divide the number by the divisor.

So 16 mod 10 = 6, because 10 fits into 16 once with remainder 6. 42 mod 10 = 2, etc

thanks for for the explanation marco, I got that far, I was just not sure about
value=1106
value%=10
its this compound operator im not sure of, what is value equal to now?

I just tried a method comparing the ints a strings using itoa()…
that didn’t go well :astonished: … not even worth posting
itoa() seems to overflow when given an unsigned int with an unsigned’esk’ value
and when blank spots in the buffer are compared they are random.

The expression:

value %= 10;

is shorthand for:

value = value % 10;

The ‘%’ operator is the modulus operator, which is equivalent to:

value = value - ((value / 10) * 10);

Note, integer division truncates, so if value was 1106 before the calculation, after ‘value %= 10’ it would hold 6.

So lets break it down:
1106 / 10 returns 110 (value / 10).
110 * 10 returns 1100 ((value / 10) * 10).
1106 - 1100 returns 6 (value - ((value / 10) * 10) or (value % 10).

MichaelMeissner:

[quote author=Paul Beaudet link=topic=158259.msg1185306#msg1185306 date=1365042913]
thanks for for the explanation marco, I got that far, I was just not sure about
value=1106
value%=10
its this compound operator im not sure of, what is value equal to now?

The expression:

value %= 10;

is shorthand for:

value = value % 10;

[/quote]

@Paul, and this shorthand notation applies to other binary operators as well: +=, -=, *=, /=.
Where applicable, a op= b; is equivalent to a = a op b.

Thus, value = 1106 followed by value %= 10 will give you value = 6.
Now, allow me to expand a little bit: if value = 1106, what is value %= 1000?

@Paul, and this shorthand notation applies to other binary operators as well: +=, -=, *=, /=.
Where applicable, a op= b; is equivalent to a = a op b.

Yes it does. It also applies to the logical operators |, &, ^, etc.

What's more, i++ is short for i+=1 which is short for i=i+1 :), but this form is only valud for ++ and --, not the other operators.

Do you know what they're trying to achieve? Unless they're trying to do something really weird, there may well be a simpler way to achieve it.

PeterH:

[quote author=Paul Beaudet link=topic=158259.msg1185238#msg1185238 date=1365037431]
I just trusted the person knew what they were doing

Do you know what they're trying to achieve? Unless they're trying to do something really weird, there may well be a simpler way to achieve it.
[/quote]

Absolutely, isolating a single digit is a very rare thing to want - usually you want to convert an integer to its
whole decimal expansion as a string in order to print it - in which case this is not the way to go about it, use
print or println. So what is the overall thing that you're trying to achieve?

So what is the overall thing that you're trying to achieve?

I'm correcting for noisy input, each of the 5 digits represents a independent button values combined into one unsigned int earlier in the program. 1 for a press, 3 for a hold and so on. In that way 300 would represent a hold on the 3rd button and 10000 would represent a press of the first. To correct for noise I need to calculate the level of difference by input.

Implicitly I can tell that if 300 hasn't been assigned to a letter my user probably doesn't wan't the letter assigned to 10000 but If there is a letter assigned to 600 which is just a longer hold of button 3 maybe they are trying to go for the letter assigned to 600. Its just more likely that is what they were trying to do, considering the input they used had not been assigned.

Applying an explicit probability algorithm that acts in a similar manner is the next step, but first I have to get those digits alone to compare the individual place cases. The way I figure it I can build up differance counter(s) and pick the assignment the generates the least difference.

There is likely a way to do this before the int is compiled, but it would conflict with another part of my program.
I'll post the link to the main body once I push the current commit, so that you folks have a better idea of the purpose of the project.

spatula:
Now, allow me to expand a little bit: if value = 1106, what is value %= 1000?

Hmmm, a bit rusty on basic math? The answer is 106.

here is the main body of code w/ out what I'm testing add for those that are curious

Hmmm, a bit rusty on basic math?

Yes, I am! but, I think spatula's intention was for me to think this out my self so I would get it

Basically 6106 or 5106 or 4106%= 1000 would be 106 thus the left most digit is being removed , and now I get it.
Thank you for bearing with me on that one, now I'll try to make a test program a report back.

I got things working :smiley:
sorry if abbreviating the variables bothers anyone. I always figure if its a problem I can just use the find & replace to fix.

#include<avr/pgmspace.h>

prog_uint16_t preDefLayout[28] PROGMEM=
//A to Z then yes then no.
{
  1100,23000,2300,21000,1000,30000,3100,20001,32000,1500,3002,3000,6600,53000,
  60000,11000,15000,6000,3200,10,600,45000,20003,33000,62000,1001,1,10000
};

unsigned int noise[5]= {3,6006,606,101,1010};
unsigned int chord;


void setup()
{
  Serial.begin(9600);
  for (int i=0;i<5;i++)
  {
    chord=filter(noise[i]);
    Serial.println(chord);
  }
}

void loop()
{
}

unsigned int filter(unsigned int noise)
{
  unsigned int correctToValue=9;
  //cant be nine so if it prints this something is wrong
  int lowPoint=15;
  for(int i=0;i<28;i++)
  {
    unsigned int largerNum;
    unsigned int compare = pgm_read_word_near(preDefLayout +i);
    unsigned int sComp=compare; //temporary second comparison
    unsigned int fComp=noise; //temp first comparison
    int pointCompare=0;
    if(fComp>sComp)
    {
      largerNum=fComp;
    }
    else
    {
      largerNum=sComp;
    };
    unsigned long mag= 1;
    while (mag*10<=largerNum)
    {
      mag*=10;
    }
    while(mag>0)
    {
      if(fComp>sComp)
        //overflow prevention
      {
        pointCompare+= fComp/mag - sComp/mag;
        Serial.print(fComp/mag - sComp/mag);
      }
      else
      {
        pointCompare+= sComp/mag-fComp/mag;
        Serial.print(sComp/mag-fComp/mag); 
      }
      fComp%=mag;
      sComp%=mag;
      mag/=10;
      Serial.print(" ");
    }
    Serial.print(" total-");
    Serial.println(pointCompare);
    if(pointCompare<lowPoint)
      //filters to the path of least resistence 
    {
      lowPoint=pointCompare;
      //set a new lowpoint
      correctToValue=compare;
      //remember the lowpoint value
    }
  }
  return correctToValue;
}

Thanks guys!

I have a couple thoughts about less iteration but I wonder If there are any inefficiencies that are obvious in what I wrote?

If it’s under your control, I suggest you rethink the way you encode those button states into an integer. Using bit masks or bit fields would make it much simpler and cleaner, and you could simply extract each set of bits representing the state of a given input and pass it to some common code to work out what to do with it, applying your fallback logic to treat a ‘hold’ as a ‘press’ etc where that was sensible. A 32-bit int would be sufficient to support eight inputs with four bits each which seems to be more than you need, and is very handily fits a hex output format with one hex character per input which help with debugging/logging.

The suggestion the encoding blows is something I agree with. However it does add a degree of complexity having the chords be represented by 32 bits vs 16 because these values are actively be drawn from and assigned in eeprom. I guess I'm just not sure how chop a long into bytes and reassemble them again.

I did show a preset layout in progmem here, but that is just to get by and doing testing on things other then the currently buggy learning algorithm. Like for instance this noise filter. In the ultimate designed working state of the device the layout is somewhat fluid, 'learning the user' initially and reassigning itself given common error making eeprom essential.

I will do some research on bit mask and bit fields though, thank you for the reference, Peter.