Pascal: Val() function is returning negative number - procedure

I've been trying to convert a string into an integer and val() procedure is returning a negative number, I thought it was becouse the string was too large (doesn't make sense, the length of the string is about 8), so I tried making the conversion manually and it returns exactly the same number val() is returning:
program a;
uses crt;
var
text:string;
number, code:integer;
begin
number:=0;
text := '3142436';
val(text, number, code);
writeln('Number: ', number);
writeln('Code: ', code);
end.
And it returns:
Number: -3292
Code: 0
Making my own conversion procedure:
program a;
uses crt;
var
numero, cod:integer;
info:string;
i:char;
begin
cod:=0;
numero:=0;
info:='3142436';
for i in info do
begin
case i of
'0': cod:= 0;
'1': cod:= 1;
'2': cod:= 2;
'3': cod:= 3;
'4': cod:= 4;
'5': cod:= 5;
'6': cod:= 6;
'7': cod:= 7;
'8': cod:= 8;
'9': cod:= 9;
end;
numero := (numero * 10) + cod;
write('Now: ', numero);
writeln(' (Adding ',cod, ')');
end;
writeln('Result: ', numero);
end.
Returns exactly the same:
Now: 3 (Adding 3)
Now: 31 (Adding 1)
Now: 314 (Adding 4)
Now: 3142 (Adding 2)
Now: 31424 (Adding 4)
Now: -13437 (Adding 3)
Now: -3292 (Adding 6)
Result: -3292
Is there something i'm doing wrong?

You are clearly using a 16-bit integer type.
3142436 is $2FF324 which truncated to a word is $F324. Interpreted as a signed integer, this is -3292 in decimal.
There are many Pascal implementations. You didn't specify which one you are using, but apparently Integer is a 16-bit integer with your current compiler settings.

just declare numero as a longint; it work's fine ^_^

Related

How to print code128C?

I am trying to print a code128C (numbers only) but I believe that the way of sending the data is incorrect ... at the time of reading the code the conversion does not result in the data initially informed.
In code128A I submit an ASCCI code, the printer converts to hex and print...the reader convert it back to ASCII.
In code128C if I submit an ASCCI, at the time of reading the reader converts to decimal, which does not result in the initial value.
EX:
128A Input: '1' Printer: 31 Reading: 1
128C Input: '1' Printer: 31 Reading: 49
I imagine that I should submit the input code already in integer .... but as the command is composed of other information I do not know how to send it in integer.
This is the code of code128A:
ComandoAnsiString := tp.cod128A('12'); //Data entry
function TTP650.cod128A(cod: AnsiString): AnsiString;
begin
// Fill out the CODE 128 printing protocol
Result := #29+#107+#73 + chr(length(cod)+2) + #123+#65 + cod;
end;
WritePrinter( HandleImp, PAnsiChar(ComandoAnsiString), Length(ComandoAnsiString),
CaracteresImpressos); //send to printer
This is the code I've been trying with code128C:
ComandoAnsiString := tp.cod128C('12');
function TTP650.cod128C(cod: AnsiString): AnsiString;
begin
Result := #29+#107+#73 + chr(length(cod)+2) + #123+#67 + cod;
end;
WritePrinter( HandleImp, PAnsiChar(ComandoAnsiString), Length(ComandoAnsiString),
CaracteresImpressos);
I'm dealing with a thermal printer and one codebar reader simple, default.
The sending codes(WritePrinter) are from the library WinSpool ... the rest are codes written by me.
Important code information is on pages 47 to 50 of the guide.
Guide
Assuming users will enter the wanted barcodes as a string of digits which may be stored somewhere as string and at the time of printing, passed to the printing function as human readable string.
The printing function will then convert to an array of bytes, packing the digits according to CODE C (each pair of two decimal digits, forming a value 00..99, stored in a byte). Iow, if the entry string of digits is e.g. '123456', then this is represented by three bytes with values 12, 34, 56.
function cod128C(const cod: string): TBytes;
const
GS = 29; // GS - Print bar code
k = 107; // k - -"-
m = 73; // m - CODE128
CS = 123; // { - select code set //}
CC = 67; // C - CODE C
var
i, len, n, x: integer;
s: string;
begin
len := Length(cod);
if len = 0 then exit;
// raise for odd number of digits in cod, ...
// if Odd(len) then
// raise Exception.Create('cod must have even number of digits');
s := cod;
// ... alternatively assume a preceeding zero digit before the first digit
// in cod
if Odd(len) then
begin
s := '0'+s;
inc(len);
end;
len := len div 2; // we pack 2 digits into one byte
SetLength(result, 6 + len);
result[0] := GS;
result[1] := k;
result[2] := m;
result[3] := 2 + len; // length of cod, + 2 for following code set selector
result[4] := CS;
result[5] := CC;
n := length(s);
i := 1; // index to S
x := 6; // index to result
while i < n do
begin
result[x] := StrToInt(MidStr(s, i, 2));
inc(i, 2);
inc(x, 1);
end;
end;
And with a form with a button, edit and memo you can test the function and send it to your printer with the following.
procedure TForm1.Button1Click(Sender: TObject);
var
cmnd: TBytes;
i: integer;
s: string;
begin
cmnd := cod128C(Edit1.Text);
for i := 0 to Length(cmnd)-1 do
s := s+IntToStr(cmnd[i])+', ';
Memo1.Lines.Add(s);
WritePrinter( HandleImp, #cmnd[0], Length(cmnd), CaracteresImpressos);
end;
You may want to add a check for only decimal digits in the input string, but I leave that to you.

How to cast a record's attributes to integer and back?

I have written the following record type with implicit operators to cast between this record type and a string. It represents a standard weather code which briefly describes current weather conditions:
type
TDayNight = (dnDay, dnNight);
TCloudCode = (ccClear = 0, ccAlmostClear = 1, ccHalfCloudy = 2, ccBroken = 3,
ccOvercast = 4, ccThinClouds = 5, ccFog = 6);
TPrecipCode = (pcNone = 0, pcSlight = 1, pcShowers = 2, pcPrecip = 3, pcThunder = 4);
TPrecipTypeCode = (ptRain = 0, ptSleet = 1, ptSnow = 2);
TWeatherCode = record
public
DayNight: TDayNight;
Clouds: TCloudCode;
Precip: TPrecipCode;
PrecipType: TPrecipTypeCode;
class operator Implicit(const Value: TWeatherCode): String;
class operator Implicit(const Value: String): TWeatherCode;
function Description: String;
function DayNightStr: String;
end;
implementation
{ TWeatherCode }
class operator TWeatherCode.Implicit(const Value: TWeatherCode): String;
begin
case Value.DayNight of
dnDay: Result:= 'd';
dnNight: Result:= 'n';
end;
Result:= Result + IntToStr(Integer(Value.Clouds));
Result:= Result + IntToStr(Integer(Value.Precip));
Result:= Result + IntToStr(Integer(Value.PrecipType));
end;
class operator TWeatherCode.Implicit(const Value: String): TWeatherCode;
begin
if Length(Value) <> 4 then raise Exception.Create('Value must be 4 characters.');
case Value[1] of
'd','D': Result.DayNight:= TDayNight.dnDay;
'n','N': Result.DayNight:= TDayNight.dnNight;
else raise Exception.Create('First value must be either d, D, n, or N.');
end;
if Value[2] in ['0'..'6'] then
Result.Clouds:= TCloudCode(StrToIntDef(Value[2], 0))
else
raise Exception.Create('Second value must be between 0 and 6.');
if Value[3] in ['0'..'4'] then
Result.Precip:= TPrecipCode(StrToIntDef(Value[3], 0))
else
raise Exception.Create('Third value must be between 0 and 4.');
if Value[4] in ['0'..'2'] then
Result.PrecipType:= TPrecipTypeCode(StrToIntDef(Value[4], 0))
else
raise Exception.Create('Fourth value must be between 0 and 2.');
end;
function TWeatherCode.DayNightStr: String;
begin
case DayNight of
dnDay: Result:= 'Day';
dnNight: Result:= 'Night';
end;
end;
function TWeatherCode.Description: String;
begin
case Clouds of
ccClear: Result:= 'Clear';
ccAlmostClear: Result:= 'Mostly Clear';
ccHalfCloudy: Result:= 'Partly Cloudy';
ccBroken: Result:= 'Cloudy';
ccOvercast: Result:= 'Overcast';
ccThinClouds: Result:= 'Thin High Clouds';
ccFog: Result:= 'Fog';
end;
case PrecipType of
ptRain: begin
case Precip of
pcNone: Result:= Result + '';
pcSlight: Result:= Result + ' with Light Rain';
pcShowers: Result:= Result + ' with Rain Showers';
pcPrecip: Result:= Result + ' with Rain';
pcThunder: Result:= Result + ' with Rain and Thunderstorms';
end;
end;
ptSleet: begin
case Precip of
pcNone: Result:= Result + '';
pcSlight: Result:= Result + ' with Light Sleet';
pcShowers: Result:= Result + ' with Sleet Showers';
pcPrecip: Result:= Result + ' with Sleet';
pcThunder: Result:= Result + ' with Sleet and Thunderstorms';
end;
end;
ptSnow: begin
case Precip of
pcNone: Result:= Result + '';
pcSlight: Result:= Result + ' with Light Snow';
pcShowers: Result:= Result + ' with Snow Showers';
pcPrecip: Result:= Result + ' with Snow';
pcThunder: Result:= Result + ' with Snow and Thunderstorms';
end;
end;
end;
end;
Examples of strings that can be cast to and from this type are...
d310 = Cloudy and Light Rain (Day)
d440 = Overcast with Rain and Thunderstorms (Day)
n100 = Mostly Clear (Night)
This string will always be in this format, and will always be 4 characters: 1 letter and 3 numbers. In reality, you can look at it as the following options:
0, 1
0, 1, 2, 3, 4, 5, 6
0, 1, 2, 3, 4
0, 1, 2
What I would like to do is also provide an option to implicitly cast it to an integer, or even byte, if I can get it small enough. I would hate however to have to add a ton of if/then/else or case statements.
I know that it is possible to take a given (small) set of characters and cast them to a single value. However, I have no idea how it's done. I do know, for example, that this technique is used in places such as the flags on DrawTextEx and other similar WinAPI calls. I think this may relate to the usage of shr / shl but I have no idea how to use those, and am terrible at that type of math.
How can I cast these 4 attributes combined into a single integer or byte, and cast them back?
The simplest thing would be to pack it into 32-bit signed or unsigned integer.
I'd prefer unsigned one (aka Cardinal )
You say - "will always be 4 characters: 1 letter and 3 numbers".
And by "character" you mean a lower Latin character.
Those characters are well represented by single-byte AnsiChar type.
Warning: in different Delphi versions Char is a shortcut to either WideChar or AnsiChar types. When doing lo-level types conversion you're to avoid ambiguous higher level shortcuts and use raw types.
Same goes for string -> UnicodeString or AnsiString ambiguity.
class operator TWeatherCode.Implicit(const Value: TWeatherCode): Cardinal;
var R: packed array [1..4] of AnsiChar absolute Result;
begin
Assert( SizeOf( R ) = SizeOf ( Result ) );
// safety check - if we ( or future Delphi versions ) screwed data sizes
// or data alignment in memory - it should "go out with a bang" rather
// than corrupting your data covertly
case Value.DayNight of
dnDay: R[1] := 'd';
dnNight: R[1] := 'n';
else raise ERangeError.Create('DayNight time is incorrect!');
// future extensibility safety check needed.
// Compiler is right with Warnings here
end;
R[2] := AnsiChar(Ord('0') + Ord(Value.Clouds));
R[3] := AnsiChar(Ord('0') + Ord(Value.Precip));
R[4] := AnsiChar(Ord('0') + Ord(Value.PrecipType));
end;
Similar thing to go back.
class operator TWeatherCode.Implicit(const Value: Cardinal): TWeatherCode;
var V: packed array [1..4] of AnsiChar absolute Value;
B: array [2..4] of Byte;
begin
Assert( SizeOf( V ) = SizeOf ( Value ) );
// safety check - if we ( or future Delphi versions ) screwed data sizes
// or data alignment in memory - it should "go out with a bang" rather
// than corrupting your data covertly
case UpCase(V[1]) of
'D': Value.DayNight:= TDayNight.dnDay;
'N': Value.DayNight:= TDayNight.dnNight;
else raise .....
end;
B[2] := Ord(V[2]) - Ord('0');
B[3]....
B[4]....
// again: error-checking is going first, before actual processing legit values. that makes it harder to forget ;-)
if (B[2] < Low(Value.Clouds)) or (B[2] > High(Value.Clouds)) then
raise ERangeError(ClassName + ' unpacking from Cardinal, #2 element is: ' + V[2] );
Value.Clouds := TCloudCode( B[2] );
.......
end;
UPD. Good question about assertions below. I hope in more or less modern Delphi that assertion should be rewritten into compile-time check. I am not totally sure of syntax, I almost never used it, but it should be something like that:
// Assert( SizeOf( R ) = SizeOf ( Result ) );
{$IF SizeOf( R ) <> SizeOf ( Result )}
{$MESSAGE FATAL 'Data size mismatch, byte-tossing operations are broken!'}
{$IFEND}
Now back to packing into one byte.... Simple bits-jockey, slicing your byte into four independent parts, it would not do.
See - https://en.wikipedia.org/wiki/Power_of_two
Your components are requiring the following cells:
0 to 1 => 0..1 => 1 bit
0 to 6 => 0..7 => 3 bits
0 to 4 => 0..7 => 3 bits
0 to 2 => 0..3 => 2 bits
1+3+3+2 = 9 > 8 bits = 1 byte.
Still you can try to get along with variable-base https://en.wikipedia.org/wiki/Positional_notation
Total number of combinations is 2*7*5*3 = 210 combinations. Less than 256 in one byte.
So you may get away with something like that:
Result :=
Ord(Value.DayNight) + 2*(
Ord(Value.Clouds) + 7*(
Ord(Value.Precip) + 5*(
Ord(Value.PrecipType) + 3*(
0 {no more 'digits' }
))));
This would do the trick, but i'd be very wary about it. The more you pack the data - the less redundancy it has. The less redundancy - the more chance that a random erratic value would look LIKE some legit data.
Also that gives you no room for future extension,
Imagine in future the #3 element would be extended from 0, 1, 2, 3, 4 range to 0 to 5 range. You would have to change the formula. But... would you really know to do it? Or would your old program be fed with new data? And if you do change the formula - how would you be able to tell bytes calculated with new and old formulas???
Frankly, I did similar tricks to pack dates into two bytes.
But I had 100% warranty I would never extend those dates, and extra I have 100% means to tell written date from non-initialized space, and - yet another extra - in case of extension required, I knew I would be able to drop that obsoleted scheme it completely and start afresh in another memory location. No compatibility with older data would be ever required. I am not so sure about your case.
You can declare your record with variant part as following
TWeatherCode = record
public
class operator Implicit(const Value: TWeatherCode): String;
class operator Implicit(const Value: String): TWeatherCode;
class operator Implicit(const Value: TWeatherCode): Cardinal;
class operator Implicit(const Value: Cardinal): TWeatherCode;
function Description: String;
function DayNightStr: String;
public
case Storage: Boolean of
True: (
DayNight: TDayNight;
Clouds: TCloudCode;
Precip: TPrecipCode;
PrecipType: TPrecipTypeCode);
False: (IntValue: Cardinal);
end;
...
class operator TWeatherCode.Implicit(const Value: TWeatherCode): Cardinal;
begin
Result := Value.IntValue;
end;
class operator TWeatherCode.Implicit(const Value: Cardinal): TWeatherCode;
begin
Result.IntValue := Value;
end;
in this case you can either assign individual fields or IntValue, they will use the same memory.

access violation 0040690B delphi

My code works but keeps giving me access violation error.
" Access violation at address 00440690B in module. read of address 01F62C42."
what is wrong? and how can I make it work?
The second loop does nothing. please help!
Var
num1, num2, k : Integer;
LL : string;
begin
LL := ' ';
num1 := 4;
num2 := 4;
for k := 1 to 7 do
begin
LL[num1] := '*';
LL[num2] := '*';
redt.Lines.Add(LL);
num1 := num1 +1;
num2 := num2 -1;
end;
for k := 1 to 3 do
redt.Lines.Add(' * ');
end;
My code works.
No, it does not. You are accessing elements of LL that are out-of-bounds. In the final iteration of the first loop, num1 has value 10, and num2 has value -2. Both of these are out-of-bounds when used as indices for LL. Valid indices for LL are 1 to 7. So I guess that the first loop should run for 1 to 4.
If you would enable range checking in the compiler options, the compiler would be able to tell you this. I cannot stress enough the importance of using range checking. Use it, and let the compiler find your defects.

String to BCD (embarcadero delphi)

Edit:
I have (test file in ascii) the following record in ascii: "000000000.00"
I need to output it ISO upon parsing it's counter part in BCD (the other test file in bcd/ebcdic). I believe it takes 6 char in BCD and 11 in ascii.
So my need was something that could convert it back and forth.
First I thought of taking each chars, feed it to a convert function and convert it back hence my messed up question.
I hope i'm more clear.
Yain
Dr. Peter Below (of Team B) donated these in the old Borland Delphi newsgroups a few years ago:
// NO NEGATIVE NUMBERS either direction.
// BCD to Integer
function BCDToInteger(Value: Integer): Integer;
begin
Result := (Value and $F);
Result := Result + (((Value shr 4) and $F) * 10);
Result := Result + (((Value shr 8) and $F) * 100);
Result := Result + (((Value shr 16) and $F) * 1000);
end;
// Integer to BCD
function IntegerToBCD(Value: Integer): Integer;
begin
Result := Value div 1000 mod 10;
Result := (Result shl 4) or Value div 100 mod 10;
Result := (Result shl 4) or Value div 10 mod 10;
Result := (Result shl 4) or Value mod 10;
end;
As you may know, the ASCII codes of the numerals 0 through 9 are 48 through 57. Thus, if you convert each character in turn to its ASCII equivalent and subtract 48, you get its numerical value. Then you multiply by ten, and add the next number. In pseudo code (sorry, not a delphi guy):
def bcdToInt( string ):
val = 0
for each ch in string:
val = 10 * val + ascii(ch) - 48;
return val;
If your "string" in fact contains "true BCD values" (that is, numbers from 0 to 9, rather than their ASCII equivalent 48 to 57), then don't subtract the 48 in the above code. Finally, if two BCD values are tucked into a single byte, you would access successive members with a bitwise AND with 0x0F (15). But in that case, Ken White's solution is clearly more helpful. I hope this is enough to get you going.
functions below work for 8 digit hexadecimal and BCD values.
function BCDToInteger(Value: DWORD): Integer;
const Multipliers:array[1..8] of Integer=(1, 10, 100, 1000, 10000, 100000, 1000000, 10000000);
var j:Integer;
begin
Result:=0;
for j:=1 to 8 do //8 digits
Result:=Result+(((Value shr ((j-1)*4)) and $0F) * Multipliers[j]);
end;//BCDToInteger
function IntegerToBCD(Value: DWORD): Integer;
const Dividers:array[1..8] of Integer=(1, 10, 100, 1000, 10000, 100000, 1000000, 10000000);
var j:Integer;
begin
Result:=0;
for j:=8 downto 1 do //8 digits
Result:=(Result shl 4) or ((Value div Dividers[j]) mod 10);
end;//IntegerToBCD

How to keep 2 decimal places in Delphi?

I have selected columns from a database table and want this data with two decimal places only. I have:
SQL.Strings = ('select '#9'my_index '#9'his_index,'...
What is that #9?
How can I deal with the data I selected to make it only keep two decimal places?
I am very new to Delphi.
#9 is the character with code 9, TAB.
If you want to convert a floating point value to a string with 2 decimal places you use one of the formatting functions, e.g. Format():
var
d: Double;
s: string;
...
d := Sqrt(2.0);
s := Format('%.2f', [d]);
function Round2(aValue:double):double;
begin
Round2:=Round(aValue*100)/100;
end;
#9 is the tab character.
If f is a floating-point variable, you can do FormatFloat('#.##', f) to obtain a string representation of f with no more than 2 decimals.
For N Places behind the seperator use
function round_n(f:double; n:nativeint):double;
var i,m : nativeint;
begin
m := 10;
for i := 1 to pred(n) do
m := m * 10;
f := f * m;
f := round(f);
result := f / m;
end;
For Float to Float (with 2 decimal places, say) rounding check this from documentation. Gives sufficient examples too. It uses banker's rounding.
x := RoundTo(1.235, -2); //gives 1.24
Note that there is a difference between simply truncating to two decimal places (like in Format()), rounding to integer, and rounding to float.
Nowadays the SysUtils unit contains the solution:
System.SysUtils.FloatToStrF( singleValue, 7, ffFixed, 2 );
System.SysUtils.FloatToStrF( doubleValue, 15, ffFixed, 2 );
You can pass +1 TFormatSettings parameter if the requiered decimal/thousand separator differ from the current system locale settings.
The internal float format routines only work with simple numbers > 1
You need to do something more complicated for a general purpose decimal place limiter that works correctly on both fixed point and values < 1 with scientific notation.
I use this routine
function TForm1.Flt2str(Avalue:double; ADigits:integer):string;
var v:double; p:integer; e:string;
begin
if abs(Avalue)<1 then
begin
result:=floatTostr(Avalue);
p:=pos('E',result);
if p>0 then
begin
e:=copy(result,p,length(result));
setlength(result,p-1);
v:=RoundTo(StrToFloat(result),-Adigits);
result:=FloatToStr(v)+e;
end else
result:=FloatToStr(RoundTo(Avalue,-Adigits));
end
else
result:=FloatToStr(RoundTo(Avalue,-Adigits));
end;
So, with digits=2, 1.2349 rounds to 1.23 and 1.2349E-17 rounds to 1.23E-17
This worked for me :
Function RoundingUserDefineDecaimalPart(FloatNum: Double; NoOfDecPart: integer): Double;
Var
ls_FloatNumber: String;
Begin
ls_FloatNumber := FloatToStr(FloatNum);
IF Pos('.', ls_FloatNumber) > 0 Then
Result := StrToFloat
(copy(ls_FloatNumber, 1, Pos('.', ls_FloatNumber) - 1) + '.' + copy
(ls_FloatNumber, Pos('.', ls_FloatNumber) + 1, NoOfDecPart))
Else
Result := FloatNum;
End;
Function RealFormat(FloatNum: Double): string;
Var
ls_FloatNumber: String;
Begin
ls_FloatNumber:=StringReplace(FloatToStr(FloatNum),',','.',[rfReplaceAll]);
IF Pos('.', ls_FloatNumber) > 0 Then
Result :=
(copy(ls_FloatNumber, 1, Pos('.', ls_FloatNumber) - 1) + '.' + copy
(ls_FloatNumber, Pos('.', ls_FloatNumber) + 1, 2))
Else
Result := FloatToStr(FloatNum);
End;

Resources