Delphi XE7 using decimal in editbox to divide - delphi

Please help:
I have two edit boxes on my form. The first one I use to type in an amount. The second one I use to divide the amount with. The problem is I try a number with a decimal like 5.5 and I keep on getting the error: "'5.5' is not a valid integer value".
Here is the code that I use:
var igroei,ipen, iper : integer;
rgroei, rper : real;
begin
ipen := strtoint(edtpen.Text); //the amount enter like 35060
iper := strtoint(edtper.Text); // The number use for the percentage like 5.5
iper := iper div 100;
rgroei := ipen + iper;
pnlpm.Caption := floattostrF(rgroei,ffcurrency,8,2);
end;
Thank you

5.5 is indeed not a valid integer. It is a floating point value. Use StrToFloat() instead of StrToInt(), and use Extended instead of Integer for the variable type.
var
ipen, iper, rgroei : Extended;
begin
ipen := StrToFloat(edtpen.Text); //the amount enter like 35060
iper := StrToFloat(edtper.Text); // The number use for the percentage like 5.5
iper := iper / 100.0;
rgroei := ipen + iper;
pnlpm.Caption := FloatToStrF(rgroei, ffcurrency, 8, 2);
end;
You should read the following to get started:
Integer and floating point numbers: The different number types in Delphi

Related

Using FormatFloat in FastReport VCL 5 scripts

I am trying to print a currency formatted value to a TfrxMemoView on the report with the following script:
procedure txCreditLimitOnBeforePrint(Sender: TfrxComponent);
begin
if <TRAN."CREDITAPPROVED"> = 1 then
txCreditLimit.Text := 'Credit Limit: ' + FormatFloat('%2.2m', <TRAN."CREDITLIMIT">)
else
txCreditLimit.Text := '';
end;
But all that I get out is %2.2m instead of the actual value. What am I doing wrong?
The function FormatFloat in FastReport is working like FormatFloat in Delphi, so you might use:
procedure txCreditLimitOnBeforePrint(Sender: TfrxComponent);
begin
if <TRAN."CREDITAPPROVED"> = 1 then
txCreditLimit.Text := 'Credit Limit: ' + FormatFloat('#,##0.00 €', <TRAN."CREDITLIMIT">)
else
txCreditLimit.Text := '';
end;
Since FormatFloat does not support system currency another way could be to use a memo bound to your dataset containing the expression like e.g. Credit Limit: [TRAN."CREDITLIMIT"] and format this memo in the Object Inspector, with the syntax you mentioned.
You condition for printing would change to:
procedure txCreditLimitOnBeforePrint(Sender: TfrxComponent);
begin
txCreditLimit.Visible := <TRAN."CREDITAPPROVED"> = 1;
end
Expressions enclosed in square brackets will be calculated in TextObjects, so for example
[<DS."a">] * 2 := [<DS."a"> + <DS."a">] will lead to an output of: 12.50 € * 2 = 25.00 €
if the format of the TfrxMemoView is defined as %2.2m. In the shown example both terms (included in square brackets) are formatted, the second one is in addition calculated.

Delphi XE2 Rounding with DecimalRounding_JH1

Because of a documented rounding issue in Delphi XE2, we are using a special rounding unit available on the Embarcadero site named DecimalRounding_JH1 to achieve true bankers rounding. A link to the unit can be found here:
DecimalRounding_JH1
Using this unit's DecimalRound function with numbers containing a large number of decimal place we
This is the rounding routine from the DecimalRounding_JH1 unit. In our example we call this DecimalRound function with the following parameters (166426800, 12, MaxRelErrDbl, drHalfEven) where maxRelErrDbl = 2.2204460493e-16 * 1.234375 * 2
Function DecimalRound(Value: extended; NDFD: integer; MaxRelErr: double;
Ctrl: tDecimalRoundingCtrl = drHalfEven): extended;
{ The DecimalRounding function is for doing the best possible job of rounding
floating binary point numbers to the specified (NDFD) number of decimal
fraction digits. MaxRelErr is the maximum relative error that will allowed
when determining when to apply the rounding rule. }
var i64, j64: Int64; k: integer; m, ScaledVal, ScaledErr: extended;
begin
If IsNaN(Value) or (Ctrl = drNone)
then begin Result := Value; EXIT end;
Assert(MaxRelErr > 0,
'MaxRelErr param in call to DecimalRound() must be greater than zero.');
{ Compute 10^NDFD and scale the Value and MaxError: }
m := 1; For k := 1 to abs(NDFD) do m := m*10;
If NDFD >= 0
then begin
ScaledVal := Value * m;
ScaledErr := abs(MaxRelErr*Value) * m;
end
else begin
ScaledVal := Value / m;
ScaledErr := abs(MaxRelErr*Value) / m;
end;
{ Do the diferent basic types separately: }
Case Ctrl of
drHalfEven: begin
**i64 := round((ScaledVal - ScaledErr));**
The last line is where we get a floating point error.
Any thoughts on why this error is occurring?
If you get an exception, that means you cannot represent your value as an double within specified error range.
In other words, the maxRelErrDbl is too small.
Try with maxRelErrDbl = 0,0000000001 or something to test if I am right.

Subtract until reach desired value

Good morning all.
I'm currently trying to figure out something that i'm confident is simple enough but is proving to be a task and a half to actually work out.
I'm working on a project that's designed to minimize drive usage by relocating various files elsewhere. I've got an array (0..12) of int64 values that contains the file sizes of the files i might potentially want to move. The array is ordered in a way that's predicted largest file size down to predicted smallest file size. I've also got the names of these files stored in a different array (known as WoWData, also [0..12]). I've then got an "installation size", and a "desired size".
My task is to calculate which files i need to move in order to bring the "installation size" down to the "desired size" by going through the array of file sizes, and taking the value away from the Installation size until i reach <= desired size.
Here's some sample code (Delphi/Firemonkey) i've been trying to work with. It's confusing me trying to figure out how to go about such a task and so there'll no doubt be a lot of issues with it;
Global Vars;
_WoWDataFileSize : Array [0..12] of Int64;
// "TBWoWDir" is a TTrackBar (Firemonkey)
var
TotalSize, ReqSize, DiffSize, CurDiff : Int64;
i : Integer;
begin
// Set up initial values to work with
ReqSize := Round(TBWoWDir.Value); // Requested Size
TotalSize := Round(TBWoWDir.Max); // Actual installation size
CurDiff := 0; // Assume as "Current Difference in size"
// Calculate difference between install and requested size
DiffSize := TotalSize - ReqSize; // This calculates correctly
// The below is what i'm struggling with
repeat
for i := Low(_WoWDataFileSize) to High(_WoWDataFileSize) do
begin
CurDiff := ReqSize - _WoWDataFileSize[i];
end;
until CurDiff <= ReqSize;
end;
I did try using just a repeat .. until loop without the for loop, but again, i'm getting far too confused while trying to figure it out.
Let me provide an example. Let's assume that _WoWDataFileSize[0] is 200, and _WoWDataFileSize[1] through to _WoWDataFileSize[12] are the same value as their array index (e.g. _WoWDataFileSize[6] = 6, _WoWDataFileSize[8] = 8, etc).
If i wanted to calculate the value of 150 (which would be 200 - 12 - 11 - 10 - 9 - 8, or Array[0] - Array[12] - Array[11] - Array[10] - Array[9] - Array[8] according to the array), and get a list of files i need to move to meet this requirement from the WoWData array, how would i write the routine?
150 could be replaced by any number as i'm working towards a dynamic user-requested size specified by TBWoWDir.Value.
I'm thinking i might need to do a While loop and use i := i+1 setup. Realistically, i could go through and hardcode it so it takes away one value in the array at a time and check each time to see if i'm <= desired value-- it'd be 2-3 lines for each item (so a total of 24-36 lines), but this is both messy to maintain and not optimal. I'm interested to see how it would be done in a loop. I typically don't have trouble with loops, but this is hardly a standard one for me.
curdiff:= 0;
i:= Low(_WoWDataFileSize) - 1;
while (curdiff <= reqsize) and (i < High(_WoWDataFileSize)) do
begin
inc (i);
curdiff:= curdiff + _WoWDataFileSize[i];
end;
At the end of the loop, either you've attained the required reduction in size or you've iterated through the entire array.
It is IMHO just two line missing in your code :o)
CurDiff := ReqSize;
// repeat
for i := Low(_WoWDataFileSize) to High(_WoWDataFileSize) do
begin
CurDiff := CurrDiff - _WoWDataFileSize[i];
if CurDiff <= ReqSize then break; // breaks the for..to loop
end;
// until CurDiff <= ReqSize;
EDIT No need for the repeat...until loop
But IMHO it is not very useful only to count the sizes without storing which files match.
So using a CustomObject and Lists (thanx to Generics) it will be very simple:
type
TFileObject = class
private
FName : string;
FSize : Int64;
public
constructor Create( AName : string; ASize : Int64 );
published
property Name : string read FName;
property Size : Int64 read FSize;
end;
procedure MoveFileObject(AMaxSize : Int64; ASrcList, ATarList : TList<TFileObject> );
var
LItem : TFileObject;
LSize : Int64;
begin
LSize := 0;
for LItem in ASrcList do
begin
if LSize + LItem.Size <= AMaxSize then
begin
LSize := LSize + LItem.Size;
ATarList.Add( LItem );
end;
end;
end;
Thanks to everyone for their answers, i figured out where i was going wrong. When i was calculating in my initial question, i'd forgotten to account for my division on the values (for the sake of showing MB instead of Bytes as TBWoWDir.Value was livebound to a TLabel.text, but the actual size was being divided before assigning TBWoWDir.Max).
Thanks to a few tweaks from an answer by No'am Newman, i managed to figure this out for myself. Here's how i got the result i was after (or much closer to it);
Global Vars;
_WoWDataFileSize : Array [0..12] of Int64;
Global Const;
_WoWData : Array [0..12] of String;
// "TBWoWDir" is a TTrackBar (Firemonkey)
[...]
var
ReqSize : int64;
DiffSize, CurDiff : Int64;
i, ii : Integer;
FilesTot : Integer;
FILESMSG : String;
begin
// Set up initial values to work with
ReqSize := Round(TBWoWDir.Value) * 1024 * 1024; // Requested Size - Multiplied from formatting
TotalSize := Round(TBWoWDir.Max) * 1024 * 1024; // Actual installation size - Multiplied from formatting
DiffSize := TotalSize - ReqSize; // Calculate Difference
CurDiff := 0; // Reset Current Difference
i := -1; // Reset i
repeat
inc (i); // Increment i
CurDiff := CurDiff + _WoWDataFileSize[i]; // Add current array item file size to CurDiff
until (CurDiff >= (DiffSize)) or (i >= 12); // Repeat until we reach ideal size or the end of the array
// Calculate which array item we stopped at
for ii := 0 to i do // use i from previous loop as the max
begin
FILESMSG := FILESMSG + 'File: ' + WoWData[ii] +
' | Size: ' + IntToStr(_WoWDataFileSize[ii])+' '#13#10;
FilesTot := FilesTot + _WoWDataFileSize[ii];
end;
// Show Message providing details
ShowMessage('CurDiff:' + IntToStr(CurDiff div 1024 div 1024) +
' | DiffSize: ' + IntToStr(DiffSize div 1024 div 1024) +
' | Array i: ' +
IntToStr(i) +#13#10+
'Difference between CurDiff and DiffSize: '+ IntToStr(((DiffSize div 1024 div 1024) - (CurDiff div 1024 div 1024)))+#13#10#13#10+
'File Details' +#13#10#13#10+
FilesMsg +#13#10#13#10+
'Total Size: ' + IntToStr(FilesTot));
end;
The code is there to tell me which files i need to copy (so modifying it to copy the files now isn't too difficult), and the whole ShowMessage is there for self-proof (as i use ShowMessage during development when i need to verify a value is returning correctly, as i'm sure many others do as well).

Adjust display gamma value

I am looking into modifying brightness/contrast/gamma of my display i found an api whose purpose i think is this but i didn't had much success implementing it... here is the code
var
i,j:Integer;
buf:array [0..2,0..255] of Word;
wBright:Word;
myDC:HDC;
begin
myDC:=GetDc(GetDesktopWindow);
GetDeviceGammaRamp(mydc,buf);
for i:=0 to 2 do
for j:=0 to 255 do
begin
buf[i][j]:=buf[i][j] + 100; //if i don't modify the values the api works
end;
SetDeviceGammaRamp(mydc,buf);
end;
I will be grateful if you point me into right direction. Thanks.
The last error says : The parameter is incorrect
The values in the array must really be a ramp, i.e. they map the possible R, G and B values to a brightness value. This way you can create funny effects too, but not with the routine below. Found something like this on the web:
uses Windows;
// SetDisplayBrightness
//
// Changes the brightness of the entire screen.
// This function may not work properly in some video cards.
//
// The Brightness parameter has the following meaning:
//
// 128 = normal brightness
// above 128 = brighter
// below 128 = darker
function SetDisplayBrightness(Brightness: Byte): Boolean;
var
GammaDC: HDC;
GammaArray: array[0..2, 0..255] of Word;
I, Value: Integer;
begin
Result := False;
GammaDC := GetDC(0);
if GammaDC <> 0 then
begin
for I := 0 to 255 do
begin
Value := I * (Brightness + 128);
if Value > 65535 then
Value := 65535;
GammaArray[0, I] := Value; // R value of I is mapped to brightness of Value
GammaArray[1, I] := Value; // G value of I is mapped to brightness of Value
GammaArray[2, I] := Value; // B value of I is mapped to brightness of Value
end;
// Note: BOOL will be converted to Boolean here.
Result := SetDeviceGammaRamp(GammaDC, GammaArray);
ReleaseDC(0, GammaDC);
end;
end;
Unfortunately, in my Win7 VM in Parallels on a Mac, I can't test his, but it should work on most normal Windows PCs.
Edit
FWIW, I ran it in my Win7 VM and the routine returns True. If I use other values, e.g.
Value := 127 * I;
the routine returns False and
ShowMessage(SysErrorMessage(GetLastError));
displays
The parameter is incorrect
Changing this to:
Value := 128 * I;
returns True again. I assume the values must form some kind of slope (or ramp). This routine creates a linear ramp. I guess you can also use other kinds, e.g. a sigmoid, to achieve other effects, like higher contrast.
I can't, of course, see any differences in brightness in the VM, sorry.
Update: But it seems to work for David Heffernan and I could just test it on my sister in law's laptop, and there it works too.

Converting float or negative integer to hexadecimal in Borland Delphi

Ive written a program that communicate with some hardware using a serial connection.
It sends a lot of hexadecimal values my way (sensor readings) and every once in a while it sends a negative value.
ex.
i receive a hexadecimal value : FFFFF5D6
and i have to convert it into : -2602
another problem i have is that i can't convert a float into hex and back.
Are there any simple ways of doing this?
You can "convert" from hex to float by using an integer large enough to cover the float value used, then using the ABSOLUTE keyword. All that is really doing is encoding the memory of the value as an integer. Be very careful to use types which are exactly the same size (you can use SIZEOF to find the memory size of a value). If you need an odd size, then absolute against an array of byte and loop through and convert to/from each byte (which would be two characters hex).
the ABSOLUTE keyword forces two variables to START at the same memory address, any value written from one is immediately available in the other.
var
fDecimal : Double; // size = 8 bytes
fInteger : Int64 absolute fDecimal; // size = 8 bytes
begin
fDecimal := 3.14;
ShowMessage(format('%x=%f',[fInteger,fDecimal]));
fInteger := StrToInt64('$1234123412341234');
ShowMessage(FloatToStr(fDecimal)+'='+Format('%x',[fInteger]));
end;
here is the routine for floats with odd sizes:
var
fDecimal : extended;
fInteger : array[1..10] of byte absolute fDecimal;
sHex : string;
iX : integer;
begin
ShowMessage(IntToStr(SizeOf(fDecimal))+':'+IntToStr(SizeOf(fInteger)));
fDecimal := 3.14;
sHex := '';
for iX := 1 to 10 do
sHex := sHex + IntToHex(fInteger[iX],2);
ShowMessage(sHex);
// clear the value
fDecimal := 0.0;
// Reload the value
for iX := 1 to (Length(sHex) DIV 2) do
fInteger[iX] := StrToInt('$'+Copy(sHex,(Ix*2)-1,2));
ShowMessage(FloatToStr(fDecimal));
end;
to convert a hex string into a integer, you can use the StrToInt Function , also you can check the TryStrToInt function (wich returns False if string does not represent a valid number).
uses
SysUtils;
var
ivalue : integer;
begin
ivalue:=StrToInt('$FFFFF5D6'); // Hexadecimal values start with a '$' in Delphi
..
end;
For the Hexadecimal representation of a float number, you can check theses articles.
http://www.merlyn.demon.co.uk/pas-type.htm#Str
http://www.merlyn.demon.co.uk/pas-real.htm
http://www.merlyn.demon.co.uk/programs/hexfloat.pas (source code example)
I've never seen a float represented in hex, so you'd have to figure out exactly what format the device is using for that. For the negative number case, you'll need to use HexToInt to covert it to an integer, and then determine if that integer is larger than whatever threshold value represents MaxInt for the hardware's integer data type. If it's bigger than that, it's a negative number, which means you'll need to, IIRC, get the number's 1s complement and convert it to negative.
If you want to separate the exponent and the significand, you can use a variant record:
TExtRec = packed record
case Boolean of
false:
(AValue: Extended);
true:
(ASignificand: uint64; ASignExp: uint16;)
end;
I think this helps to understand the structure of the floating point number.
Example usage:
var
r: TExtRec;
begin
r.AValue := 123.567;
ShowMessage(IntToHex(r.ASignExp) + IntToHex(r.ASignificand));
end;
Output:
4005F7224DD2F1A9FBE7
You can calculate it back:
v = (-1)s * 2(e-16383) * (i.f)
With
e = $4005 = 16389 and
i.f = $F7224DD2F1A9FBE7
i.f = 1.930734374999999999954029827886614611998084001243114471435546875
v=123.566999999999999997057908984743335167877376079559326171875
To convert i.f, i've used a binary converter.

Resources