blash
asked on
How to make a checksum procedure?
Hi guys,
I need to make a checksum procedure. Can someone help me?
I have a 15 digit number:
Num:=220840001229500
The last 2 digits are zeroes by default.
To get a "control number" I have to perform the following calculation:
I divide Num with 97, thats:
220840001229500:97=2276701 043603.09x xxx
Now I have to use the second digit of this result - the 9.
(97+1)-9=89
So 89 is my "control number",
and now at the end, Num: the last 2 zeroes get replaced with the "control number" and Num2: would be
Num2:=2208400012295/89
Greetings, Blash
I need to make a checksum procedure. Can someone help me?
I have a 15 digit number:
Num:=220840001229500
The last 2 digits are zeroes by default.
To get a "control number" I have to perform the following calculation:
I divide Num with 97, thats:
220840001229500:97=2276701
Now I have to use the second digit of this result - the 9.
(97+1)-9=89
So 89 is my "control number",
and now at the end, Num: the last 2 zeroes get replaced with the "control number" and Num2: would be
Num2:=2208400012295/89
Greetings, Blash
ASKER
Dear Neil,
What if my Num: is a DBEdit7.Text?
And how do I declare an Int64
Blash
What if my Num: is a DBEdit7.Text?
And how do I declare an Int64
Blash
add to the neil code:
var
num,num2,idigit:int64;
rtemp:extended;
begin
Num := strtoint(DBEdit7.Text);{22 0840001229 500}
rTemp := Num / 97;
iDigit := TRUNC(ABS(FRAC(rTemp)) * 100) DIV 10;
iDigit := (97 + 1) - iDigit;
Num2 := (Num DIV 100) * 100 + iDigit;
end;
var
num,num2,idigit:int64;
rtemp:extended;
begin
Num := strtoint(DBEdit7.Text);{22
rTemp := Num / 97;
iDigit := TRUNC(ABS(FRAC(rTemp)) * 100) DIV 10;
iDigit := (97 + 1) - iDigit;
Num2 := (Num DIV 100) * 100 + iDigit;
end;
Exactly as f15iaf says although personally I'd check the StrToInt conversion:
TRY
Num := StrToInt(DBEdit7.Text);
EXCEPT
//Do something useful
END;
The Neil =:)
TRY
Num := StrToInt(DBEdit7.Text);
EXCEPT
//Do something useful
END;
The Neil =:)
ASKER
The code works,
but I get a Error message:
EConvertError with message "220401000207585" is not a valid integer value.
Why?
but I get a Error message:
EConvertError with message "220401000207585" is not a valid integer value.
Why?
Ahhh. IntToStr can't handle the size of the value. What you need to do is either write your own routine to do it or use this one
FUNCTION BigStrToInt(sValue : STRING): INT64;
VAR
iCount : LONGINT;
BEGIN
Result := 0;
FOR iCount := 1 TO Length(sValue)
DO
Result := Result * 10 + StrToInt(sValue[iCount]);
END;
It then just gets called in the same way as IntToStr:
VAR
iNum : INT64;
begin
iNum := BigStrToInt('2204010002075 85');
...
The Neil =:)
FUNCTION BigStrToInt(sValue : STRING): INT64;
VAR
iCount : LONGINT;
BEGIN
Result := 0;
FOR iCount := 1 TO Length(sValue)
DO
Result := Result * 10 + StrToInt(sValue[iCount]);
END;
It then just gets called in the same way as IntToStr:
VAR
iNum : INT64;
begin
iNum := BigStrToInt('2204010002075
...
The Neil =:)
ASKER
Dear The Neil,
I think that your BigStrToInt function works.
But now I get another Error message after running the code block. I get:
EAccessViolation at address...Read of address FFFFFFFF.
I am appending the code now. Can you see something wrong there?
procedure TForm1.Table2BeforePost(Da taSet: TDataSet);
var
Num, Num2, idigit: int64;
rtemp: extended;
//Od The Neil
iNum: int64;
//
begin
//moe,ama samo dopola vrsi rabota
// if Pos('4',DBEdit7.Text)>0 then
if Copy(DBEdit7.Text,1,1) = '4' then //Od Mohhamed
begin
ShowMessage('Value must not start with a 4');
Table2.Cancel;
end;
//Od Neil
iNum:=BigStrToInt(DBEdit7. Text);
rTemp:=iNum/97;
iDigit:=TRUNC(ABS(FRAC(rTe mp))*100)D IV 10;
iDigit:=(97+1)-iDigit;
Num2:=(iNum DIV 100)*100+iDigit;
//Od Neil
if iDigit<>89 then
begin
ShowMessage('the bank account is not correct');
Table2.Cancel;
end;
end;
I think that your BigStrToInt function works.
But now I get another Error message after running the code block. I get:
EAccessViolation at address...Read of address FFFFFFFF.
I am appending the code now. Can you see something wrong there?
procedure TForm1.Table2BeforePost(Da
var
Num, Num2, idigit: int64;
rtemp: extended;
//Od The Neil
iNum: int64;
//
begin
//moe,ama samo dopola vrsi rabota
// if Pos('4',DBEdit7.Text)>0 then
if Copy(DBEdit7.Text,1,1) = '4' then //Od Mohhamed
begin
ShowMessage('Value must not start with a 4');
Table2.Cancel;
end;
//Od Neil
iNum:=BigStrToInt(DBEdit7.
rTemp:=iNum/97;
iDigit:=TRUNC(ABS(FRAC(rTe
iDigit:=(97+1)-iDigit;
Num2:=(iNum DIV 100)*100+iDigit;
//Od Neil
if iDigit<>89 then
begin
ShowMessage('the bank account is not correct');
Table2.Cancel;
end;
end;
Well it depends on which values you're putting into it that are causing the error (the access voliation itself means nothing). I did spot one thing though (but I don't think it's the problem), try adding a Exit to the first IF statement:
if Copy(DBEdit7.Text,1,1) = '4' then //Od Mohhamed
begin
ShowMessage('Value must not start with a 4');
Table2.Cancel;
Exit;
end;
Beyond that then it's a case of looking at the data. Can you post a value (or values) that are causing problems?
The Neil =:)
if Copy(DBEdit7.Text,1,1) = '4' then //Od Mohhamed
begin
ShowMessage('Value must not start with a 4');
Table2.Cancel;
Exit;
end;
Beyond that then it's a case of looking at the data. Can you post a value (or values) that are causing problems?
The Neil =:)
ASKER
Dear The Neil,
After cheking out my question, I saw that I must redefine it. I'll do that later during the day. I'll try that "Exit;" anyway. Thanks for helping me.
Greetings, Blash
After cheking out my question, I saw that I must redefine it. I'll do that later during the day. I'll try that "Exit;" anyway. Thanks for helping me.
Greetings, Blash
ASKER
Hi The Neil,
The 15 digit number is:
Num:=220840001229500
The last 2 digits are not zeroes by default.
To get the "control number" I have to perform the following calculation:
I divide Num with 97, but I need the reminder, that's:
220840001229500 mod 97, so the reminder is 9.
So now I need this reminder "9" for the "control number":
(97+1)-"reminder"=(97+1)-9 =89
So now my Num2: is:
2208400012295/89
If the "reminder" would be "0" then by default the "control number" would be "89".
I hope I got it right now.
Thanks, Blash
The 15 digit number is:
Num:=220840001229500
The last 2 digits are not zeroes by default.
To get the "control number" I have to perform the following calculation:
I divide Num with 97, but I need the reminder, that's:
220840001229500 mod 97, so the reminder is 9.
So now I need this reminder "9" for the "control number":
(97+1)-"reminder"=(97+1)-9
So now my Num2: is:
2208400012295/89
If the "reminder" would be "0" then by default the "control number" would be "89".
I hope I got it right now.
Thanks, Blash
Well using the steps you've mentioned the code below will do what you want. I've included loads of comments so hopefully if there is a problem with the approach then we should be able to spot it:
procedure TForm1.Button1Click(Sender : TObject);
FUNCTION BigStrToInt(sValue : STRING): INT64;
VAR
iCount : LONGINT;
BEGIN
Result := 0;
FOR iCount := 1 TO Length(sValue)
DO
Result := Result * 10 + StrToInt(sValue[iCount]);
END;
VAR
iValue : INT64;
iResult : INT64;
sValue : STRING;
begin
sValue := '220840001229500';
//Get the stribg into an integer
iValue := BigStrToInt(sValue);
//We're only interested in the final two digits for calculating the checksum
//BUT we need remember the rest of the value (minus the last two digits) so
//strip off the last two digitd by dividing by 100
iResult := iValue DIV 100;
//Divide the COMPLETE value by 97
iValue := iValue MOD 97;
//Calculate the checksum
iValue := (97 + 1) - iValue;
//Add the two checksum digits to the end of the value
//iResult is the original number but with the last two digits stripped. If we
//add on two extra zeroes (by multiplying by 100), we can then add the
//checksum value straight onto the end to give us a final value
iResult := iResult * 100 + iValue;
ShowMessage('Result: ' + IntToStr(iResult));
end;
The Neil =:)
procedure TForm1.Button1Click(Sender
FUNCTION BigStrToInt(sValue : STRING): INT64;
VAR
iCount : LONGINT;
BEGIN
Result := 0;
FOR iCount := 1 TO Length(sValue)
DO
Result := Result * 10 + StrToInt(sValue[iCount]);
END;
VAR
iValue : INT64;
iResult : INT64;
sValue : STRING;
begin
sValue := '220840001229500';
//Get the stribg into an integer
iValue := BigStrToInt(sValue);
//We're only interested in the final two digits for calculating the checksum
//BUT we need remember the rest of the value (minus the last two digits) so
//strip off the last two digitd by dividing by 100
iResult := iValue DIV 100;
//Divide the COMPLETE value by 97
iValue := iValue MOD 97;
//Calculate the checksum
iValue := (97 + 1) - iValue;
//Add the two checksum digits to the end of the value
//iResult is the original number but with the last two digits stripped. If we
//add on two extra zeroes (by multiplying by 100), we can then add the
//checksum value straight onto the end to give us a final value
iResult := iResult * 100 + iValue;
ShowMessage('Result: ' + IntToStr(iResult));
end;
The Neil =:)
ASKER
Dear The Neil :)))
The code works prefectly, only one thing:
How can I say in code at the place where:
sValue:='220840001229500';
take care only for the first 13 digits,leave the 14th and 15th alone (thats taken care later with:
iResult:=iResult*100+iValu e;
Thanks Blash ;)))
The code works prefectly, only one thing:
How can I say in code at the place where:
sValue:='220840001229500';
take care only for the first 13 digits,leave the 14th and 15th alone (thats taken care later with:
iResult:=iResult*100+iValu
Thanks Blash ;)))
I'm not sure what you mean. As it stands, the code strips off the last two digits (14th and 15th) works out the checksum and then adds the two new values onto the end when it's finished (so you end up with the same number of digits). It's effectively ignoring the 14th and 15th digits and only basing it's calculation on the first 13
The Neil =:(
The Neil =:(
ASKER
Dear The Neil :)))
So sorry that I'm nagging you with my stupid question. You have more then deserved my pityful 50 points. Have you had a nice weekend? I hope this would be the last that you hear from me - concerning this question.
Your code works perfectly for me if I, for example, have this number:
220401000207682, but only if I enter it as:
220401000207600.
In fact I need, after running your procedure that:
sValue: would be the same as iResult:
I hope I've explained it now.
Sincerely, Blash
So sorry that I'm nagging you with my stupid question. You have more then deserved my pityful 50 points. Have you had a nice weekend? I hope this would be the last that you hear from me - concerning this question.
Your code works perfectly for me if I, for example, have this number:
220401000207682, but only if I enter it as:
220401000207600.
In fact I need, after running your procedure that:
sValue: would be the same as iResult:
I hope I've explained it now.
Sincerely, Blash
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
That was perfect.
Thank you The Neil.
Hope we'll meet again on EE.
Blash :)))
Thank you The Neil.
Hope we'll meet again on EE.
Blash :)))
Anytime
The Neil =:)
The Neil =:)
Num := 220840001229500;
rTemp := Num / 97;
iDigit := TRUNC(ABS(FRAC(rTemp)) * 100) DIV 10;
iDigit := (97 + 1) - iDigit;
Num2 := (Num DIV 100) * 100 + iDigit;
You will need to declare Num and Num2 as Int64 variables (Longint ain't big enough)
The Neil =:)