0

I'm currently working on a windows form in VS2010 that is supposed to create UPC-A for new part numbers and store them in a database. So far I'm still trying to get the pieces together and I'm having issues with calculating the check digit. I came up with the following two scenarios:

Scenario 1: Do the calculation the way we currently do it in Excel:

string value = uPCDataSet.UPC.Rows[uPCDataSet.UPC.Rows.Count - 1]["UPCNumber"].ToString();
string manCode = value.Substring(1, 5);
string prodCode = value.Substring(7, 5);
int first = Math.Abs(Convert.ToInt32(value));

while (first >= 10)
first /= 10;

int chkDigitSubtotal;

string UPCNumber = first + manCode + prodCode;

chkDigitSubtotal = Convert.ToInt32((UPCNumber.Substring(1, 1)) + (UPCNumber.Substring(3, 1)) + 
(UPCNumber.Substring(5, 1)) + (UPCNumber.Substring(7, 1)) + (UPCNumber.Substring(9, 1)) + 
(UPCNumber.Substring(11, 1)));

chkDigitSubtotal = (3 * chkDigitSubtotal) + Convert.ToInt32((UPCNumber.Substring(2, 1)) + 
(UPCNumber.Substring(4, 1)) + (UPCNumber.Substring(6, 1)) + (UPCNumber.Substring(8, 1)) + 
(UPCNumber.Substring(10, 1)));

 string chkDigit = ((300 - chkDigitSubtotal).ToString()).Substring(12, 1);

When I run this code, I get an error "Value was either too large or too small for an Int32". I don't understand why since "value" is a varchar with 12 characters (they are all numbers).

Scenario 2: I found a code snipped online. This code works, but gives me the wrong check digit. I'm using a UPC that we calculated using your Excel sheet:

string value = "606891001678"; //valid UPC with check digit
string UPCBody = value.Substring(0, 11);
int sum = 0;
bool odd = true;

for (int i = value.Length - 1; i >= 0; i--)
{
    if (odd == true)
    {
        int tSum = Convert.ToInt32(value[i].ToString()) * 2;

        if (tSum >= 10)
        {
            string tData = tSum.ToString();
            tSum = Convert.ToInt32(tData[0].ToString()) + Convert.ToInt32(tData[1].ToString());
        }
        sum += tSum;
    }
    else
        sum += Convert.ToInt32(value[i].ToString());

    odd = !odd;
}

int result = (((sum / 10)+1) *10) - sum;
result = result % 10;
MessageBox.Show(UPCBody + " & " + result);

In this example the check digit obviously should be 8, but it returns 2. I've spent pretty much all day on this and could use some advice. Why am I getting the error on the first scenario and why am I getting a different check digit in the second scenario from what it should be?

Thanks in advance for your help!

Chris

EDIT:

I deleted two previous edits since the code was flawed in a sense that I didn't get the correct results. I found out that we use Azalea barcodes and they have their own method of calculating the check digit (see ChkDigitSubtotal). So the below code works and gives me the correct check digit for my scenario. I think this code will work up to chkDigitSubtotal for all UPC-A calculations. Thanks to Harrison for his great guidance and resourceful answer!

string value = uPCDataSet.UPC.Rows[uPCDataSet.UPC.Rows.Count - 1]
["UPCNumber"].ToString();
long chkDigitOdd;
long chkDigitEven;
long chkDigitSubtotal;
string UPCNumber = value.Substring(0, 11);
chkDigitOdd = Convert.ToInt64(UPCNumber.Substring(0, 1)) +
Convert.ToInt64(UPCNumber.Substring(2, 1)) + Convert.ToInt64(UPCNumber.Substring(4, 1)) 
+ Convert.ToInt64(UPCNumber.Substring(6, 1)) + Convert.ToInt64(UPCNumber.Substring(8, 
1)) + Convert.ToInt64(UPCNumber.Substring(10, 1));
chkDigitOdd = (3 * chkDigitOdd);
chkDigitEven = Convert.ToInt64(UPCNumber.Substring(1, 1)) + 
Convert.ToInt64(UPCNumber.Substring(3, 1)) + Convert.ToInt64(UPCNumber.Substring(5, 1)) 
+ Convert.ToInt64(UPCNumber.Substring(7, 1)) + Convert.ToInt64(UPCNumber.Substring(9, 
1));
chkDigitSubtotal = (300-(chkDigitEven + chkDigitOdd));
string chkDigit = chkDigitSubtotal.ToString();
chkDigit = chkDigit.Substring(chkDigit.Length - 1, 1);
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
campagnolo_1
  • 2,710
  • 1
  • 17
  • 25
  • I don't know the answer to your problem, but C# doesn't have a type called "varchar". That sounds like a type in a database. Int32 can handle numbers from -2147483648 to +2147483647, which, while it's a 10 digit number, does not support the full range you'll need. Add in the check digit and you'll need 11 digits. Try using the `Decimal` type, which supports something like 28 digits. – Steve Oct 24 '13 at 20:06
  • @Steve, varchar is indeed the field type in the SQL database where "value" comes from. I will look into Decimal and see if it gets me anywhere. Thanks for the hint! – campagnolo_1 Oct 24 '13 at 20:09
  • Once you load the value from the database into your .NET program, you're working with .NET CLR types. By the way, here is a list of value types in C#: http://msdn.microsoft.com/en-us/library/s1ax56ch(v=vs.100).aspx – Steve Oct 24 '13 at 20:13
  • In your calculation for `chkDigitSubtotal` (in the first example) you add 6 1 digit strings and convert it to a number. The most that could be is 999,999. Then you multiply by 3 = 2,999,997 and add again a 5 digit string maxing out at 99,999 = 3099996 max. Now you take this and subtract it from 300 = -3,099,696. I see 8 characters including the minus sign (not including commas). I'm not sure how you would take the 12th character of a string that is 8 characters long? Did I make a mistake in the calculation? – Harrison Oct 24 '13 at 20:27

2 Answers2

1

Based on what I'm reading on wikipedia your doing the calculation incorrectly in the first example.

  • String.Substring + String.Subtring or "1" + "1" = "11". You are looking for 1+1=2. You need to convert each substring to int prior to adding.

+ Operator (C# Reference)

Binary + operators are predefined for numeric and string types. For numeric types, + computes the sum of its two operands. When one or both operands are of type string, + concatenates the string representations of the operands.

  • String.Substring is 0 based so you are missing the String.Substring(0,1) for your even digits

String.Substring Method

startIndex: The zero-based starting character position of a substring in this instance.

  • Your checkdigit string attempts to take the 12th digit of a string which is less than 12 digits. Also, this isn't the calculation as seen in the link. It's looking for 10 - mod 10 of that number. This is also happening in your updated edit in the line

string chkDigit = ((300 - chkDigitSubtotal).ToString()).Substring(12, 1);

You are attempting to take a Substring from the 12th 0 based character, or 13th character for a length of 1. However, the value of chkDigitSubtotal will not be that large/long.

As far as your error, As Golden Dragon states in his answer your are converting a 12 characcter string to a number, which won't fit into an Int32 and you should use a long.

int first = Math.Abs(Convert.ToInt32(value));

goes to

long first = Math.Abs(Convert.ToInt64(value));

I would check your calculation is actually functioning logically in the previous steps first.

Update

In your edit 2 it looks like your last line has the variables around the % operator reversed. You want to take the remainder of 109 divided by 10 (which is 9) and your code takes the remainder of 10 divided by 109 (which is 0) So change.

chkDigitSubtotal = 10 - (10 % (chkDigitEven + chkDigitOdd));

to

chkDigitSubtotal = 10 - ((chkDigitEven + chkDigitOdd) % 10);

Now 10 - 9 = 1 which is your checkDigit.

Harrison
  • 3,843
  • 7
  • 22
  • 49
0

If value is a 12 digit long string, then it is much too large to fit into an int. Use a long instead

Golden Dragon
  • 511
  • 5
  • 13