i want to create a random number in delphi and assign it to file as a file name. I managed to do that but when i click button to generate number it always start with a 0. Any idea how to fix it
procedure TForm1.Button1Click(Sender: TObject);
var
test:integer;
begin
test:= random(8686868686868);
edit1.Text:= inttostr(test);
end;
end.
As user246408 said you should use Randomize to initialize the random number generator with a random value. Also if you want to limit the returned numbers to positive integers, use the predefined MaxInt constant.
The overloaded function System.Random that returns an integer has the following signature:
function Random(const ARange: Integer): Integer;
and returns an integer X which satisfies the formula 0 <= X < ARange.
To prevent a 0 value, you can add a constant of your choise, like
procedure TForm17.Button2Click(Sender: TObject);
const
MinRandomValue = 100000;
var
test:integer;
begin
test:= random(MaxInt-MinRandomValue)+MinRandomValue;
edit1.Text:= inttostr(test);
end;
(MinRandomValue subtracted from MaxInt to prevent overflow)
or, you can use System.Math.RandomRange
test := RandomRange(100000, MaxInt);
Documented here
Your code has 2 problems.
You don't call Randomize, that is why you always get zero as the
first "random" value.
You use too large value 8686868686868 for Random range, it
exceeds 32-bit boundary and equivalent to 2444814356.
if you need just a single "random" value use
procedure TForm1.Button1Click(Sender: TObject);
var
test:integer;
begin
Randomize;
test:= random($7FFFFFFF);
edit1.Text:= inttostr(test);
end;
Related
I am having one Delphi XE2 Project to check one Hexadecimal Value from Registry Key MyCompanyName\1. If the Hexadecimal Value is 13, then some message will be there else some other message will be there.
So I have defined the following codes:
procedure TMainForm.BitBtn01Click(Sender: TObject);
var
RegistryEntry : TRegistry;
begin
RegistryEntry := TRegistry.Create(KEY_READ or KEY_WOW64_64KEY);
RegistryEntry.RootKey := HKEY_LOCAL_MACHINE;
if (RegistryEntry.KeyExists('SOFTWARE\MyCompanyName\1\')) then
begin
if (RegistryEntry.OpenKey('SOFTWARE\MyCompanyName\1\',true)) then
begin
if (RegistryEntry.ReadString('SettingValue') = '0x00000013') then
begin
Memo01.Lines.Add('SettingHexadeciamlValue exist properly')
end
else
begin
Memo01.Lines.Add('SettingHexadeciamlValue does not exist properly')
end;
end
else
begin
if (RegistryEntry.OpenKey('SOFTWARE\MyCompanyName\1\',false)) then
begin
Memo01.Lines.Add('Unable to read RegistryKey ''MyCompanyName''Exiting.......')
end;
end;
end
else
begin
Memo01.Lines.Add('RegistryKey ''MyCompanyName'' does not exist')
end;
end;
After compilation, when I am running the application AsAdministrator, I am getting error mentioning Invalid data type for 'SettingValue'.
These values are integers, not strings, so you should use ReadInteger, not ReadString.
Now, hexadecimal is only a way of presenting an integer to the user, that is, a method of creating a 'textual representation' of the integer. For example, the integer 62 has many different textual representations:
62 (decimal)
LXII (Roman numerals)
3E (hexadecimal)
111110 (binary)
Sextiotvå (Swedish words)
etc.
If you want to display this number in hexadecimal, as the registry editor (regedit.exe) does, you can use the IntToHex function, which creates a hexadecimal textual representation of the argument integer. Example:
var
myvalue: integer;
...
myvalue := ReadInteger('SettingValue');
ShowMessage(IntToHex(myvalue, 8));
I'm going maintain and port to Delphi XE2 a bunch of very old Delphi code that is full of VarArrayCreate constructs to fake dynamic arrays having a lower bound that is not zero.
Drawbacks of using Variant types are:
quite a bit slower than native arrays (the code does a lot of complex financial calculations, so speed is important)
not type safe (especially when by accident a wrong var... constant is used, and the Variant system starts to do unwanted conversions or rounding)
Both could become moot if I could use dynamic arrays.
Good thing about variant arrays is that they can have non-zero lower bounds.
What I recollect is that dynamic arrays used to always start at a lower bound of zero.
Is this still true? In other words: Is it possible to have dynamic arrays start at a different bound than zero?
As an illustration a before/after example for a specific case (single dimensional, but the code is full of multi-dimensional arrays, and besides varDouble, the code also uses various other varXXX data types that TVarData allows to use):
function CalculateVector(aSV: TStrings): Variant;
var
I: Integer;
begin
Result := VarArrayCreate([1,aSV.Count-1],varDouble);
for I := 1 to aSV.Count-1 do
Result[I] := CalculateItem(aSV, I);
end;
The CalculateItem function returns Double. Bounds are from 1 to aSV.Count-1.
Current replacement is like this, trading the space zeroth element of Result for improved compile time checking:
type
TVector = array of Double;
function CalculateVector(aSV: TStrings): TVector;
var
I: Integer;
begin
SetLength(Result, aSV.Count); // lower bound is zero, we start at 1 so we ignore the zeroth element
for I := 1 to aSV.Count-1 do
Result[I] := CalculateItem(aSV, I);
end;
Dynamic arrays always have a lower bound of 0. So, low(A) equals 0 for all dynamic arrays. This is even true for empty dynamic arrays, i.e. nil.
From the documentation:
Dynamic arrays are always integer-indexed, always starting from 0.
Having answered your direct question already, I also offer you the beginnings of a generic class that you can use in your porting.
type
TSpecifiedBoundsArray<T> = class
private
FValues: TArray<T>;
FLow: Integer;
function GetHigh: Integer;
procedure SetHigh(Value: Integer);
function GetLength: Integer;
procedure SetLength(Value: Integer);
function GetItem(Index: Integer): T;
procedure SetItem(Index: Integer; const Value: T);
public
property Low: Integer read FLow write FLow;
property High: Integer read GetHigh write SetHigh;
property Length: Integer read GetLength write SetLength;
property Items[Index: Integer]: T read GetItem write SetItem; default;
end;
{ TSpecifiedBoundsArray<T> }
function TSpecifiedBoundsArray<T>.GetHigh: Integer;
begin
Result := FLow+System.High(FValues);
end;
procedure TSpecifiedBoundsArray<T>.SetHigh(Value: Integer);
begin
SetLength(FValues, 1+Value-FLow);
end;
function TSpecifiedBoundsArray<T>.GetLength: Integer;
begin
Result := System.Length(FValues);
end;
procedure TSpecifiedBoundsArray<T>.SetLength(Value: Integer);
begin
System.SetLength(FValues, Value);
end;
function TSpecifiedBoundsArray<T>.GetItem(Index: Integer): T;
begin
Result := FValues[Index-FLow];
end;
function TSpecifiedBoundsArray<T>.SetItem(Index: Integer; const Value: T);
begin
FValues[Index-FLow] := Value;
end;
I think it's pretty obvious how this works. I contemplated using a record but I consider that to be unworkable. That's down to the mix between value type semantics for FLow and reference type semantics for FValues. So, I think a class is best here.
It also behaves rather weirdly when you modify Low.
No doubt you'd want to extend this. You'd add a SetBounds, a copy to, a copy from and so on. But I think you may find it useful. It certainly shows how you can make an object that looks very much like an array with non-zero lower bound.
I have the following procedure :
procedure GetDegree(const num : DWORD ; var degree : DWORD ; min ,sec : Extended);
begin
degree := num div (500*60*60);
min := num div (500*60) - degree *60;
sec := num/500 - min *60 - degree *60*60;
end;
After degree variable gets assigned the debugger skips to the end of the procedure . Why is that?
It's an optimisation. The variables min and sec are passed by value. That means that modifications to them are not seen by the caller and are private to this procedure. Hence the compiler can work out that assigning to them is pointless. The values assigned to the variables can never be read. So the compiler elects to save time and skip the assignments.
I expect that you meant to declare the procedure like this:
procedure GetDegree(const num: DWORD; var degree: DWORD; var min, sec: Extended);
As I said in your previous question, there's not really much point in using Extended. You would be better off with one of the standard floating point types, Single or Double. Or even using the generic Real which maps to Double.
Also, you have declared min to be of floating point type, but the calculation computes an integer. My answer to your previous question is quite precise in this regard.
I would recommend that you create a record to hold these values. Passing three separate variables around makes your function interfaces very messy and breaks encapsulation. These three values only have meaning when consider as a whole.
type
TGlobalCoordinate = record
Degrees: Integer;
Minutes: Integer;
Seconds: Real;
end;
function LongLatToGlobalCoordinate(const LongLat: DWORD): TGlobalCoordinate;
begin
Result.Degrees := LongLat div (500*60*60);
Result.Minutes := LongLat div (500*60) - Result.Degrees*60;
Result.Seconds := LongLat/500 - Result.Minutes*60 - Result.Degrees*60*60;
end;
function GlobalCoordinateToLongLat(const Coord: TGlobalCoordinate): DWORD;
begin
Result := Round(500*(Coord.Seconds + Coord.Minutes*60 + Coord.Degrees*60*60));
end;
TNumberbox and TSpinEdit return values defined as type single. I want to use these values to do simple integer arithmetic, but I can't cast them successfully to the more generalized integer type, and Delphi gives me compile-time errors if I try to just use them as integers. This code, for example, fails with
"E2010 Incompatible types: 'Int64' and 'Extended'":
var
sMinutes: single;
T: TDatetime;
begin
sMinutes :=Numberbox1.value;
T :=incminute(Now,sMinutes);
All I want to do here is have the user give me a number of minutes and then increment a datetime value accordingly. Nothing I've tried enables me to use that single in this way.
What am I missing??
Just truncate the value before using it:
var
Minutes: Integer;
T: TDateTime;
begin
Minutes := Trunc(NumberBox1.Value);
T := IncMinute(Now, Minutes);
end;
Depending on your particular needs, you may need to use Round instead. It will correctly round to the nearest integer value, making sure that 1.999999999999 correctly becomes integer 2; Trunc would result in 1 instead. (Thanks to Heartware for this reminder.)
var
Minutes: Integer;
T: TDateTime;
begin
Minutes := Round(NumberBox1.Value);
T := IncMinute(Now, Minutes);
end;
Trunc and Round are in in the System unit.
I'm doing some heavy work on large integer numbers in UInt64 values, and was wondering if Delphi has an integer square root function.
Fow now I'm using Trunc(Sqrt(x*1.0)) but I guess there must be a more performant way, perhaps with a snippet of inline assembler? (Sqrt(x)with x:UInt64 throws an invalid type compiler error in D7, hence the *1.0 bit.)
I am very far from an expert on assembly, so this answer is just me fooling around.
However, this seems to work:
function isqrt(const X: Extended): integer;
asm
fld X
fsqrt
fistp #Result
fwait
end;
as long as you set the FPU control word's rounding setting to "truncate" prior to calling isqrt. The easiest way might be to define the helper function
function SetupRoundModeForSqrti: word;
begin
result := Get8087CW;
Set8087CW(result or $600);
end;
and then you can do
procedure TForm1.FormCreate(Sender: TObject);
var
oldCW: word;
begin
oldCW := SetupRoundModeForSqrti; // setup CW
// Compute a few million integer square roots using isqrt here
Set8087CW(oldCW); // restore CW
end;
Test
Does this really improve performance? Well, I tested
procedure TForm1.FormCreate(Sender: TObject);
var
oldCW: word;
p1, p2: Int64;
i: Integer;
s1, s2: string;
const
N = 10000000;
begin
oldCW := SetupRoundModeForSqrti;
QueryPerformanceCounter(p1);
for i := 0 to N do
Tag := isqrt(i);
QueryPerformanceCounter(p2);
s1 := inttostr(p2-p1);
QueryPerformanceCounter(p1);
for i := 0 to N do
Tag := trunc(Sqrt(i));
QueryPerformanceCounter(p2);
s2 := inttostr(p2-p1);
Set8087CW(oldCW);
ShowMessage(s1 + #13#10 + s2);
end;
and got the result
371802
371774.
Hence, it is simply not worth it. The naive approach trunc(sqrt(x)) is far easier to read and maintain, has superior future and backward compatibility, and is less prone to errors.
I believe that the answer is no it does not have an integer square root function and that your solution is reasonable.
I'm a bit surprised at the need to multiple by 1.0 to convert to a floating point value. I think that must be a Delphi bug and more recent versions certainly behave as you would wish.
This is the code I end up using, based on one of the algorhythms listed on wikipedia
type
baseint=UInt64;//or cardinal for the 32-bit version
function isqrt(x:baseint):baseint;
var
p,q:baseint;
begin
//get highest power of four
p:=0;
q:=4;
while (q<>0) and (q<=x) do
begin
p:=q;
q:=q shl 2;
end;
//
q:=0;
while p<>0 do
begin
if x>=p+q then
begin
dec(x,p);
dec(x,q);
q:=(q shr 1)+p;
end
else
q:=q shr 1;
p:=p shr 2;
end;
Result:=q;
end;