Delphi - from Integer to Byte type (negative number conversion) - delphi

I tested some code:
var
B: Byte;
I: Integer;
begin
I := -10;
B := I;
end;
And I expected to see the result in the variable In the number 10 (since this is the low byte of the type integer ). But the result was B => 246.
Logically, I understand that 246 = 256 - 10, but I can't understand why this happened?

Your expectation of the value 10 for the least significant (ls) byte of the integer with value -10 is not correct.
Negative numbers are encoded according a system called 2's complement, where a value of -1 as a four byte integer is coded as $FFFFFFFF, -2 as $FFFFFFFE, -3 as $FFFFFFFD ... -10 as $FFFFFFF6 ... and so on. This is the system used by most computers/software at present time.
There are other systems too. The one you possibly thought of is a system called Signed magnitude (see: https://en.wikipedia.org/wiki/Signed_number_representations) where the most significant bit, when set, indicates negative values, and where the actual numbers are encoded the same for both negative and positive numbers (with the inconvenience of defining two zero values, +0 and -0).

The value -10 is $FFFFFFF6 in an Integer. Assigning that to a lower-width type will simply truncate the value - that means the value in B will be $F6 and that is 246.
If you compile with range checking you will get an exception because -10 does not fit into a Byte.
If you want to turn a negative number into a positive you need to use the Abs function.

Related

I want to create a Fibonacci sequence using a for loop, but the integers are not adding up

procedure TForm1.Button1Click(Sender: TObject);
var
term1: integer;
term2: integer;
term3: integer;
j: integer;
begin
term1 := (0);
term2 := (1);
for j := 1 to 100 do;
begin
term3 :=( term1 + term2);
Memo1.Text:=inttostr(term3);
term1 := term2;
term2 := term3;
end;
end;
end.
This is what I have so far, but term1 and term2 don't want to add up. I have tried some different things, but for some reason the integers never want to add up.
There are several problems with your code
The semicolon after for j := 1 to 100 do prevents your next code that is withing begin..end block to be run in a loop. Why? The code that is to be run in each cycle of for loop is the one that follows the do until the first semicolon. Since you put semicolon just after the do this basically means that empty block of code is ran in a loop. Your begin..end block comes after that. Removing the semicolon after do will fix that.
You are using Memo1.Text:=inttostr(term3); to write the result into Memo. The problem with this is that this will rewrite entire text of the Memo every time so you will end up with only one line showing the last number. You should use Memo1.Lines.Add(inttostr(term3)); instead so that new line is added each time.
Lastly you are using Integer type for your variables. Since numbers in Fibonacci sequence grows very fast you will quickly exceed the maximum value that can be stored in Integer which in Delphi is Signed 32 bit Integer with a max value of 2147483647. You will have to use bigger integer types like 64 bit Integer type and since you are only dealing with positive numbers you should therefore use Unsigned 64 bit Integer that in declared in Delphi by UInt64 type. You can read more about Delphi default Integer types in documentation. Unfortunately not even UInt64 will is big enough for value of all first 100 numbers of Fibonacci sequence. So you will have to use one of the BigIntegers libraries for Delphi to do this properly. There are several of them available on internet.
You have an erroneous ; on your loop that you need to remove:
for j := 1 to 100 do;
^

Delphi Format Strings - limits for width and precision values?

This statement (in Delphi 7)
writeln(logfile,format('%16.16d ',[FileInfo.size])+full_name);
results in this output
0000000021239384 C:\DATA\DELPHI\sxf_archive10-13.zip
This statement
writeln(logfile,format('%17.17d ',[FileInfo.size])+full_name);
results in this output
21239384 C:\DATA\DELPHI\sxf_archive10-13.zip
The padding with leading zeros changes to leading spaces when the precision specifier is larger than 16. The help says "If the format string contains a precision specifier, it indicates that the resulting string must contain at least the specified number of digits; if the value has less digits, the resulting string is left-padded with zeros."
Is there another way to format a 20 character integer with leading zeros?
Precision of an Integer value is limited to 16 digits max. If the specified Precision is larger than 16, 0 is used instead. This is not a bug, it is hard-coded logic, and is not documented.
There are two ways you can handle this:
use an Int64 instead of an Integer. Precision for an Int64 is 32 digits max:
WriteLn(logfile, Format('%20.20d %s', [Int64(FileInfo.Size), full_name]);
Note: In Delphi 2006 and later, TSearchRec.Size is an Int64. In earlier versions, it is an Integer instead, and thus limited to 2GB. If you need to handle file sizes > 2GB in earlier versions, you can get the full 64-bit size from the TSearchRec.FindData field:
var
FileSize: ULARGE_INTEGER;
begin
FileSize.LowPart := FileInfo.FindData.nFileSizeLow;
FileSize.HighPart := FileInfo.FindData.nFileSizeHigh:
WriteLn(logfile, Format('%20.20d %s', [FileSize.QuadPart, full_name]);
end;
convert the Integer to a string without any leading zeros, and then use StringOfChar() to prepend any required zeros:
s := IntToStr(FileInfo.Size);
if Length(s) < 20 then
s := StringOfChar('0', 20-Length(s)) + s;
WriteLn(logfile, s + ' ' + full_name);

Delphi - join 2 integer in a Int64

I'm working with Delphi and Assembly, so, i had a problem. I used a instruction(RDTSC) in Assembly of getting a 64-bits read time-stamp, the instruction put the numbers separately in two registers EAX and EDX. But it's ok, i get it with Delphi Integer variables. But now, i need to join those variables in 1 of 64-bits. It's like:
Var1 = 46523
var2 = 1236
So i need to put it into one variable like:
Var3 = 465231236
it's like a StrCat, but i'm don't know how to do it. Somebody can help me?
You certainly don't want to concatenate the decimal string representations of the two values. That is not the way you are expected to combine the two 32 bit values returned from RTDSC into a 64 bit value.
Combining 46523 and 1236 should not yield 465231236. That is the wrong answer. Instead, you want to take the high order 32 bits, and put them alongside the low order 32 bits.
You are combining $0000B5BB and $00004D4. The correct answer is either $0000B5BB00004D4 or $00004D40000B5BB, depending on which of the two values are the high and low order parts.
Implement this in code, for instance, using Int64Rec:
var
Value: UInt64;
...
Int64Rec(Value).Lo := Lo;
Int64Rec(Value).Hi := Hi;
where Lo and Hi are the low and high 32 bit values returned by RTDSC.
So, bits 0 to 31 are set to the value of Lo, and bits 32 to 63 are set to the value of Hi.
Or it can be written using bitwise operations:
Value := (UInt64(Hi) shl 32) or UInt64(Lo);
If all you need to do is read the time stamp counter, then you don't need to do any of this though. You can implement the function like this:
function TimeStampCounter: UInt64;
asm
RDTSC
end;
The register calling convention requires that a 64 bit value return value is passed back to the caller in EDX:EAX. Since the RDTSC places the values in those exact registers (not a coincidence by the way), you have nothing more to do.
All of this said, rather than using the time stamp counter, it is usually preferable to use the performance counter, which is wrapped by TStopWatch from System.Diagnostics.
The simple way is to use a record
type
TMyTimestamp = record
case Boolean of
true:
( Value: Int64 );
false:
( Value1: Integer; Value2: Integer );
end;
and you can store/read each value as you like
var
ts: TMyTimestamp;
begin
ts.Value1 := 46523;
ts.Value2 := 1236;
WriteLn( ts.Value ); // -> 5308579624379
ts.Value := 5308579624379;
WriteLn( ts.Value1 ); // -> 46523
WriteLn( ts.Value2 ); // -> 1236
end;
see: Docwiki: Variant Parts in Records

Converting Integer number into hexadecimal number in delphi 7

Write a program to convert an integer number to its hexadecimal representation without using inbuilt functions.
Here is my code, but it is not working. Can anyone tell where is the mistake?
It is giving an error:
"Project raised exception class EAccessViolation with message 'Access violation at address 00453B7B in module 'Project.exe'.Write of address FFFFFFFF'.Process stopped.Use Step or Run to continue."
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,Forms,
Dialogs;
type
TForm1 = class(TForm)
end;
function hexvalue(num:Integer):Char;
var
Form1: TForm1;
implementation
{$R *.dfm}
function hexvalue(num:Integer):Char;
begin
case num of
10: Result:='A';
11: Result:='B';
12: Result:='C';
13: Result:='D';
14: Result:='E';
15: Result:='F';
else Result:=Chr(num);
end;
end;
var
intnumber,hexnumber,actualhex:String;
integernum:Integer;
i,j,k:Byte;
begin
InputQuery ('Integer Number','Enter the integer number', intnumber);
integernum:=StrToInt(intnumber);
i:=0;
while integernum >= 16 do
begin
hexnumber[i]:=hexvalue(integernum mod 16);
integernum:= integernum div 16;
Inc(i);
end;
hexnumber[i]:= hexvalue(integernum);
k:=i;
for j:=0 to k do
begin
actualhex[j]:= hexnumber[i];
Dec(i);
end;
ShowMessage(actualhex);
end.
Since this obviously is a homework assignment, I don't want to spoil it for you and write the solution, but rather attempt to guide you to the solution.
User input
In real code you would need to be prepared for any mistake from the user and check that the input really is integer numbers only and politely ask the user to correct the input if erroneous.
Conversion loop
You have got that OK, using mod 16 for each nibble of integernum and div 16 to move to the next nibble, going from units towards higher order values.
Conversion of nibble to hex character
Here you go wrong. If you would have written out also the cases for 0..9, you could have got the case statement right. As others have commented, Chr() takes an ASCII code. However, using a case statement for such a simple conversion is tedious to write and not very efficient.
What if you would have a lookup table (array) where the index (0..15) directly would give you the corresponding hex character. That would be much simpler. Something like
const
HexChars: array[_.._] of Char = ('0',_____'F')
I leave it to you to fill in the missing parts.
Forming the result (hex string)
Your second major mistake and the reason for the AV is that you did not set the length of the string hexnumber before attempting to acess the character positions. Another design flaw is that you fill in hexnumber backwards. As a result you then need an extra loop where you reverse the order to the correct one.
There are at least two solutions to solve both problems:
Since you take 32 bit integer type input, the hex representation is not more than 8 characters. Thus you can preset the length of the string to 8 and fill it in from the lower order position using 8 - i as index. As a final step you can trim the string if you like.
Don't preset the length and just concatenate as you go in the loop hexnumber := HexChars[integernum mod 16] + hexnumber;.
Negative values
You did not in any way consider the possibility of negative values in your code, so I assume it wasn't part of the task.
First mistake : String are 1 indexed. Meaning that the index of their first character is 1 and not 0. You initialize "i" to 0 and then try to set hexnumber[i].
Second mistake : Strings might be dynamic, but they don't grow automatically. If you try to access the first character of an empty string, it won't work. You need to call SetLength(HeXNumber, NumberOfDigits). You can calculate the number of digits this way :
NumberOfDigits := Trunc(Log16(integernum)) + 1;
Since Log16 isn't really something that exists, you can either use LogN(16,integernum) or (Log(IntegerNum) / Log(16)) depending on what is available in your version of Delphi.
Note that this might return an invalid value for very, very large value (high INT64 range) due to rounding errors.
If you don't want to go that road, you could replace the instruction by
hexnumber := hexvalue(integernum mod 16) + hexnumber;
which would also remove the need to invert the string at the end.
Third Mistake : Using unsigned integer for loop variable. While this is debatable, the instruction
for I := 0 to Count - 1 do
is common practice in Delphi without checking Count > 0. When count = 0 and using an unsigned loop counter, you'll either get an integer overflow (if you have them activated in your project options) or you'll loop High(I) times, which isn't what you want to be doing.
Fourth mistake : already mentionned : Result:=Chr(num) should be replaced by something like Result := InttoStr(Num)[1].
Personally, I'd implement the function using an array.
HexArr : Array[0..15] of char = ('0', '1',...,'D','E','F');
begin
if InRange(Num, 0, 15) then
Result := HexArr[Num]
else
//whatever you want
end;

Why doesn't "i := i + 1" give a range-check error for Integers and larger types?

Consider:
{$R+}
i:= 1;
While i > 0 do
i:= i + 1;
ShowMessage(IntToStr(i));
If I declare i as Byte, Word, Shortint or TinyInt I get a range-check error, as expected.
If I declare i as LongWord, Cardinal, Integer, LongInt or Int64 it just goes through the while loop and gets to show the negative or 0 value, which i gets when you pass the upper bound.
Does Delphi 7 not support range checking for 32-bit and 64-bit numbers?
The operation i + 1 doesn't actually produce a range check error. The assignment operation does.
Delphi evaluates the constant '1' as an Integer and so the right hand side will produce a result that is either an Int64 or an Integer (The larger of i's type and Integer).
If we expand the line out we get the following
temp := i + 1
i := temp
temp will either be 32 or 64 bits, and will overflow if it hits the upper bound. By the time we do the assignment, we have a perfectly valid 32 or 64bit value so there's no possibility of a range check failure if i is 32bits or more.
If i is less than 32 bits, it will raise a range check if temp is too large to fit.
For i >= 32bits, you can catch the overflow error like so:
{$R+,Q+}
...

Resources