I need to work with round or trunc functions in FreePascal with very big numbers(such as INT64) - rounding

var a,c,i,y,k:cardinal;
z:real;
check:boolean;
repet:array[1..1000] of cardinal;
tripet:array[1..1000,1..2] of real;
begin
read(c);
i:=1;
for a:=1 to (c) do
begin
z:= sqrt(c*c-a*a);
if (c=round(z)) or (round(z)=0) then continue;
if z=round(z) then
begin
check:=false;
for k:=1 to i do if repet[k]=z then check:=true;
if (check) then continue;
tripet[i][1]:=a;
tripet[i][2]:=z;
repet[i]:=a;
i:=i+1;
end;
end;
if i=1 then write('Nope');
for y:=1 to (i-1) do writeln(tripet[y][1]:0:0,' ',tripet[y][2]:0:0);
end.
The problem is in round(z) which bring too large z number.It needs Int32 type.
But I need bigger number:for istance number can between 1 and 10^12
How can i solve it in?

You use cardinal which is a 32-bit type, and probably a round to match is found. Try to either use 64-bit types or use int64(c)=round(z) to force 64-bit round?

Related

kylix AnsiCompareStr bug?

The following program tries to use AnsiCompareStr/Text:
program Project5;
{$APPTYPE CONSOLE}
uses StrUtils, SysUtils;
begin
Writeln('Ord(''-'')=', Ord('-'));
Writeln('Ord(''_'')=', Ord('_'));
Writeln('AnsiCompareStr(''-'', ''_'')=', AnsiCompareStr('-', '_'));
Writeln('AnsiCompareText(''-'', ''_'')=', AnsiCompareText('-', '_'));
Writeln('WideCompareStr(''-'', ''_'')=', WideCompareStr('-', '_'));
Writeln('WideCompareText(''-'', ''_'')=', WideCompareText('-', '_'));
Writeln('CompareStr(''-'', ''_'')=', CompareStr('-', '_'));
Writeln('CompareText(''-'', ''_'')=', CompareText('-', '_'));
Readln;
end.
When compiled with Kylix, it outputs wrong results on CentOS 5/6 x64:
Ord('-')=45
Ord('_')=95
AnsiCompareStr('-', '_')=3 <--- should be negative
AnsiCompareText('-', '_')=3 <--- should be negative
WideCompareStr('-', '_')=3 <--- should be negative
WideCompareText('-', '_')=3 <--- should be negative
CompareStr('-', '_')=-50
CompareText('-', '_')=-50
I wonder why AnsiCompareStr/Text gives wrong results ?
PS: CompareStr is considered obsolete according to http://www.delphibasics.co.uk/RTL.asp?Name=CompareStr . AnsiCompareStr is considered to be the modern, Locale safe form of CompareStr according to http://www.delphibasics.co.uk/RTL.asp?Name=AnsiCompareStr .
PS: The locale is en_US.iso885915 and/or en_US.UTF8
PS: Kylix 3 (as Delphi 7 with CrossKylix)
function AnsiCompareStr(const S1, S2: string): Integer;
begin
{$IFDEF MSWINDOWS}
Result := CompareString(LOCALE_USER_DEFAULT, 0, PChar(S1), Length(S1),
PChar(S2), Length(S2)) - 2;
{$ENDIF}
{$IFDEF LINUX}
// glibc 2.1.2 / 2.1.3 implementations of strcoll() and strxfrm()
// have severe capacity limits. Comparing two 100k strings may
// exhaust the stack and kill the process.
// Fixed in glibc 2.1.91 and later.
Result := strcoll(PChar(S1), PChar(S2));
{$ENDIF}
end;
function AnsiCompareText(const S1, S2: string): Integer;
begin
{$IFDEF MSWINDOWS}
Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PChar(S1),
Length(S1), PChar(S2), Length(S2)) - 2;
{$ENDIF}
{$IFDEF LINUX}
Result := WideCompareText(S1, S2);
{$ENDIF}
end;
AnsiCompareStr/Text are giving correct results. They reflect the ordering defined by the prevailing locale. For instance AnsiCompareStr is implemented with a simple call to strcoll from the glibc standard library.
The problem is in your expectations. I'm not sure why you expect the results you do, but it's quite reasonable to expect that glibc implements collation correctly. The order implied by strcoll is the collation order for the prevailing locale, whatever that happens to be. You didn't state that in the question.
Perhaps the clue is that you use the phrase locale safe. Well, CompareXXX are independent of locale, AnsiCompareXXX depend upon the locale. If you are looking for locale invariant ordering then AnsiCompareXXX are the wrong choice.

Inno Setup loop from A to Z

I am trying to write a function that will check for the existence of a particular directory on each drive in turn, store the path where it is found as a variable and return true if it exists and false otherwise:
function IsDirPresent(): Boolean;
var
chrDriveLetter: Char;
strMyDir: String;
begin
for chrDriveLetter := 'A' to 'Z' do
begin
if DirExists(chrDriveLetter + ':\MyDir') then
strMyDirPath := chrDriveLetter + ':\MyDir'
end;
if strMyDirPath <> '' then
Result := True;
end;
I get a Type mismatch error on my loop line when compiling this. I am struggling to work out what is wrong with the loop and haven't been able to find any information on how to correctly create a loop from A to Z in Inno Setup.
Your loop is valid for Pascal language because the Char type is ordinal and its range constants are of the same type, so I guess this is a specific limitation of the Pascal Script language notation. I don't know if there's some syntax workaround nor if the Char type is even allowed to be used for the loop control variable.
I can only provide you a workaround working with integer type loop control variable. It uses the Ord and Chr functions. The first returns the ordinal value of a char, the latter ASCII char from the ordinal value:
var
C: Char;
I: Integer;
begin
for I := Ord('A') to Ord('Z') do
begin
C := Chr(I);
...
end;
end;

Delphi memory leak in string?

I have a program which accepts an SQL query as a command-line argument, queries a PostgreSQL database and produces a file formatted in one of several ways (most often it's used to produce CSV files).
However, this program has som serious memory leaks - with one particular query that produces as 12MB file, the program uses 8GB of RAM plus several GB of swap space before the operating system kills it. I want to find the cause of this memory leak. I don't know Delphi very well (and judging by the quality of the program, neither did the original author), but I am tasked with finding a quick fix.
The following doData function portion of outputs a single row of the result set. I'd hazard a guess that the problem is with the "copy" command (creating a string on the heap that is never freed), but I'm sure someone more experienced than myself will be able to confirm this answer or point me in the right direction.
procedure doData;
var
s, fldVal : string;
i, fldLen : integer;
begin
s := '';
for i := 0 to ds.Fields.Count-1 do
begin
if (ds.Fields[i].DataType = ftDate) or
(ds.Fields[i].DataType = ftDateTime) then
begin
if psql.outDate = 'i' then
fldLen := 8
else
fldLen := 10;
if ds.Fields[i].IsNull then
fldVal := ''
else
fldVal := formatDate(ds.Fields[i].AsDateTime);
end
else
begin
fldLen := ds.Fields[i].DisplayWidth;
fldVal := ds.Fields[i].AsString;
end;
if (psql.outType = 'd') or (psql.outType = 's') then
s := s + trim(fldVal)
else if psql.outType = 'f' then
begin
s := s + fldVal;
if fldLen - length(fldVal) > 0 then
s := s + copy(spaces, 1, fldLen - length(fldVal));
// Is this a memory leak above?
end;
if psql.outType = 's' then
begin
if i < ds.Fields.Count-1 then
s := s + psql.outDelimChar;
end
else
s := s + psql.outDelimChar;
end;
writeln(psql.outPrefixData + s);
end;
There are no leaks in this code. The Delphi string type is managed by the compiler and requires no explicit memory deallocations from the programmer.
If you wish to find your leak you should include the full debug version of FastMM. This will produce diagnostics reports of any leaks in your code, including stack traces that help identify where the leaked memory was originally allocated.

Inno Setup comma error

I have GetVersion function in [Code] that returns a string like this "1004", "1003", etc.
I created this function to check the registry value for lowest version numbers and uninstall them.
Here is a snippet of the code it is giving error point to StrtoInt conversion line stating
Comma (,) expected
Here is the snippet:
function DoesOldVersionsExist(): Boolean;
var
AppVersion: integer;
mstr: string;
VersionInstalled: cardinal;
begin
AppVersion := StrToInt(GetVersion({#MyAppVersion}), 0);
...
after that line I'm simple comparing the values and return true or false. Much Appreciated.
This is what error message says:
Line 55
Column 40.
Comma (,) expected
Thanks Deanna but unfortunately that is the error message pointing to this :
AppVersion := StrToInt(GetVersion({#MyAppVersion}), 0);
^
Here is the GetVersion function:
function GetVersion(AppVersion: String): String;
var
Version: String;
CharIndex: integer;
c: char;
begin
for CharIndex := 1 to Length(AppVersion) do begin
c := AppVersion[CharIndex];
if (c <> '.') then
Version := Version + c;
end;
Result := Version;
end;
I think that you can't just have Inno Setup constants in code like this, you have to use ExpandConstant():
AppVersion := StrToInt(GetVersion(ExpandConstant('{#MyAppVersion}')), 0);
You have not given us enough information to give a definite answer, but I think that the situation is as follows.
You have defined some constant called MyAppVersion which you let the ISPP (the Inno Setup pre-processor) substitute. Now, you have not told us what type this variable is, and you have not told us what the signature of GetVersion is (in particular, what type of argument does it expect?). However, if these types are strings, you need to write
StrToInt(GetVersion('{#MyAppVersion}'), 0);
in order to obtain, say,
StrToInt(GetVersion('Some string, this is!'), 0);
instead of
StrToInt(GetVersion(Some string, this is!), 0);
which is malformed (indeed, to such an extent that it hurts my eyes to look at it).

InnoSetup & Pascal - Type mismatch error on run even after successful compile

When I compile the code below, it completes without errors, but when I attempt to run the setup file I get a type mismatch error. Can anyone tell me what might be causing it? (exact error message is "Runtime Error (at 1:66): Type Mismatch.")
[Setup]
DefaultDirName={code:AppDir}\MyApp
[Code]
function AppDir(Param: String): String;
var
Check: Integer;
begin
Check := GetWindowsVersion();
if Check = 6.0 then
Result := ExpandConstant('{userdocs}')
else
Result := ExpandConstant('{pf}');
end;
Quoting from the Inno Setup documentation for GetWindowsVersion():
Returns the version number of Windows packed into a single integer. The upper 8 bits specify the major version; the following 8 bits specify the minor version; the lower 16 bits specify the build number. For example, this function will return $05000893 on Windows 2000, which is version 5.0.2195.
You can't compare with a floating point value, you need to extract the parts of the version number, like so:
function AppDir(Param: String): String;
var
Ver: Cardinal;
VerMajor, VerMinor, BuildNum: Cardinal;
begin
Ver := GetWindowsVersion();
VerMajor := Ver shr 24;
VerMinor := (Ver shr 16) and $FF;
BuildNum := Ver and $FFFF;
if VerMajor >= 6 then
Result := ExpandConstant('{userdocs}')
else
Result := ExpandConstant('{pf}');
end;
Note that you should never check VerMajor for equality, as this would fail for either lower or higher Windows versions. Always use <= or >= instead.

Resources