Get Integer number from a Float? - delphi

I Have a number that is divided by 12 Months.
I need to get the result of the division as an Integer number.
Ex:
mTblDetailMonth.FieldByName('Target_').asfloat := (MTblDetail.FieldByName('Target_').AsInteger / 12 );
When the MTblDetail.FieldByName('Target_').AsInteger is equal to 20 and divide
20 / 12, the Result is 1.666666667.
I need to get the number 1 only and then calculate the floating decimal number.

Your question is not very clear, so here's two alternatives:
The answer to your question as it is written (assuming an integer variable years and a float variable remainder)
use trunc to get the integer part of the division result
years := trunc(MTblDetail.FieldByName('Target_').AsInteger / 12); // returns 1
remainder := MTblDetail.FieldByName('Target_').AsInteger / 12 - years; // returns 0.6666...
Since you talk about months, maybe you want to know 'years' and 'months' as integers.
If so, use div and mod operators:
years := MTblDetail.FieldByName('Target_').AsInteger div 12 ; // returns 1
months := MTblDetail.FieldByName('Target_').AsInteger mod 12 ; // returns 8

Related

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

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.

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);

Add Time to a TDateTime

I would like to add seconds to a TDateTime variable, so that the result is the top of the minute. For example, if it's 08:30:25, I want change the TDateTime variable to store 08:31:00.
I see that TDateTime has a Decode function, which I could use. There isn't, however, an encode function to put the altered time back into a TDateTime variable.
Using DateUtils it's possible to do it like this:
Uses
DateUtils;
var
Seconds : Word;
Seconds := SecondOfTheMinute(MyTime); // Seconds from last whole minute
// Seconds := SecondOf(MyTime); is equivalent to SecondOfTheMinute()
if (Seconds > 0) then
MyTime := IncSecond(MyTime,60 - Seconds);
There sure is, at least in the recent versions - see the DateUtils unit, especially all the Recode* routines and EncodeDateTime. The DateUtils unit is already available in Delphi 2010, perhaps even in earlier version.
Theory
The TDateTime data type represents number of days since 30 Dec 1899 as a real number. That is, the integral part of TDateTime is an amount of whole days, and the fractional part represents a time of day.
Practical
Therefore, your problem could be solved using simple arithmetics:
var
Days: TDateTime;
Mins: Extended; { widen TDateTime's mantissa by 11 bits to accommodate division error }
begin
Days := Date + StrToTime('08:30:25');
Writeln(DateTimeToStr(Days));
Mins := Days * 24 * 60 ; // compute minutes
Mins := Math.Ceil(Mins); // round them up
Days := Mins / (24 * 60); // and back to days
{ or as simple and concise expression as: }
// Days := Ceil(Days * MinsPerDay) / MinsPerDay;
Writeln(DateTimeToStr(Days));

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+}
...

How can I get a result larger than 2^32 from shl?

Declaration...
const
n = 2 shl 33
will set constant n to value 4 without any compiler complaint!
Also...
Caption := IntToStr(2 shl 33);
...return 4 instead 8589934592.
It looks like the compiler calculates like this:
2 shl 33 = 2 shl (33 and $1F) = 4
But without any warning or overflow.
The problem remains if we declare:
const
n: int64 = 2 shl 33;
The number in constant is still 4 instead 8589934592.
Any reasonable work around?
You're looking for the wrong results, according to both the Delphi compiler and Windows 7's calculator in programmer mode. (The answer you're wanting is actually 2 shl 32, BTW.)
You need to cast both sides of the shl to Int64:
const
n = Int64(2) shl Int64(33);
This produces
N = 17179869184;
The current documentation (for XE2, but applies to earlier versions of Delphi as well) notes this in Fundamental Integer Types. However, that page mentions only having to cast one of the operands as Int64; my test shows it to require both operands be typecast in the const declaration above - typecasting only one (regardless of which one) also resulted in `n = 4;'.

Resources