I have an output txtfile with some float numbers and I like to print in different formats, y try with:
FormatFloat('00000;000.0;00.00', val)
FormatFloat('00.00;000.0;00000', val)
But I take wrong outputs. What I need is:
If val < 10 then output like '00.00'
If 10 < val < 100 then output like '000.0'
If val > 100 then output like '00000'
It's a huge amount of float values, so, I need a low processing solution and I think more conditionals will slow down the application. ¿Any advice?
Thank you
Using conditional tests to sort the values into separate outputs is not going to affect performance in a significant way. The format process is far more elaborate. One important thing about optimization is to only walk that path if you can measure a performance hit in the actual code.
if (val < 10) then
s := FormatFloat('00.00',val)
else
if (val < 100) then
s := FormatFloat('000.0',val)
else
s := FormatFloat('00000',val);
Also consider using the thread-safe FormatFloat with a supplied FormatSettings variable.
I suppose that conditionals would work faster, but consider this sketch (care about out-of-range values):
const
FormatString: array[-1..2] of string = ('0.000', '0.00', '0.0', '0');
var
x: Double;
i: integer;
begin
x := 0.314;
for i := 1 to 4 do begin
Memo1.Lines.Add(FormatFloat(FormatString[Floor(Log10(x))], x));
x := x * 10;
end;
0.314
3.14
31.4
314
Related
I have a problem with translating VHDL to Verilog.
It's part of my source code on VHDL.
With I/O I somehow understood, but have some problems to translate this string
ib1 <= std_logic_vector(to_unsigned(i,ib1'length));
to verilog?
COMPONENT GenerateModel
PORT(
ib1 : IN std_logic_vector(3 downto 0);
);
END COMPONENT;
--Inputs
signal ib1 : std_logic_vector(3 downto 0) := (others => '0');
BEGIN
uut: GenerateModel PORT MAP (
ib1 => ib1,
);
process
begin
for i in 0 to 15 loop
ib1 <= std_logic_vector(to_unsigned(i,ib1'length));
wait for 10 ns;
end loop;
end process;
end;
To extend into Verilog from Paebbels' comment, the line you are looking at does an explicit conversion from the type of the loop variable i to the port variable ib1. In Verilog, that explicit conversion is not needed, you can just assign the port variable directly. So, for example (in Verilog IEEE 1364-1995 compatible):
integer i;
...
for (i = 0; i < 16; i = i + 1) begin
ib1 = i; // <-- The line
#10; // -- Assume 1 step is 1 ns, can specific timescale if needed
end
If you want, you can even loop through the variable directly if its of type reg (ie, not a net):
for (ib1 = 0; ib1 < 15; ib1 = ib1 + 1) begin
#10;
end
#10;
[Note that as Greg mentioned, you need to be sure you dont create an infinite loop as if ib1 is 4-bits wide, it will always be less than 16, thus I fixed the example above to loop until ib1 is 15 (4'b1111)]
How we can generate randomize number between a range in the Float numbers (in delphi xe3) ?
For example, randomize number between [0.10 to 0.90].
I need give results like:
[ 0.20 , 0.32 , 0.10 , 0.50 ]
Thanks for solutions....
Another option is to use RandomRange (returns: AFrom <= r < ATo) as follow:
RandomRange(10, 90 + 1) / 100
or
RandomRange(10, 90 + 1) * 0.01
will return numbers in the range of 0.10 to 0.90 (including 0.90)
var
float : Double;
float := Random; // Random float in range: 0 <= float < 1
float := 0.1 + float*0.8 // 0.1 <= float < 0.9
To initialize the Random number generator, make a single call to Randomizeor set the RandSeed parameter before calling the Random function for the first time.
Not doing so, generates the same sequence every time you run the program. Note however, that this sequence is not guaranteed when recompiling for another compiler version.
Try this:
function RandomRangeF(min, max: single): single;
begin
result := min + Random * (max - min);
end;
This is a bit cheeky but here goes: Depends how many numbers you want after the floating point. For example, if you want 1 number, you could generate in the 100 - 999 range and then divide by 10. Or 1000 - 9999 and divide by 100.
Hi there =) And sorry for my English, in advance
I have a task to calculate hurst exponent by method of linear regression. And I have text description of solution. It looks very easy, but always i get values, that go out from range 0..1. Usually, value is 1.9 or something similar. Sometimes it gets negative value that is close to zero.
I have looked over code about thousand times but couldn't see a mistake.
var
max_z,min_z,x_m:real; //max and min of cumulative sum and mean value of X for every Tau
st,ss,sst,st2 :real;
Al, Herst: real;
x_vr:array of double; //a piece of array with length=tau
i, j, nach: integer;
begin
//file opening and getting values of X array are in another function
nach:=3; //initial value of tau
Setlength(ln_rs,l-nach); //length of ln(R/S) array
Setlength(ln_t,l-nach); //length of ln(tau) array
Setlength(r,l-nach); //length of R array
Setlength(s,l-nach); //length of S array
//Let's start
for tau:=nach to l do //we will change tau
begin
Setlength(x_vr,tau+1); //set new local array (length=tau)
for i:=0 to length(x_vr)-1 do
x_vr[i]:=x[i];
x_m:=Mean(x_vr); //mean value
Setlength(y,tau+1); //length of array of difference from mean value
Setlength(z,tau+1); //length of array of cumulative sum
for i:=0 to tau do
y[i]:=x_vr[i]-x_m; //difference from mean value
z[0]:=y[0];
for i:=1 to tau do //cumulative sum
for j :=i downto 0 do
z[i]:=z[i]+y[j];
max_z:=z[0];
for i:=1 to tau do //max of cumulative sum
max_z:=max(max_z,z[i]);
min_z:=z[0];
for i:=1 to tau do //min of cumulative sum
min_z:=min(min_z,z[i]);
r[tau-nach]:=max_z-min_z; //R value
s[tau-nach]:=0;
for i:=0 to tau do
s[tau-nach]:=power(y[i],2)+s[tau-nach]; //S value
s[tau-nach]:=sqrt(s[tau-nach]/(tau+1));
//new array values
ln_rs[tau-nach]:=Ln(R[tau-nach]/S[tau-nach]); // ln(R/S)
ln_t[tau-nach]:=ln(tau); // ln (tau)
end; //End of calculating
//Method of Least squares
for i:=0 to length(ln_rs)-1 do
st:=st+ln_t[i];
st:=(1/length(ln_rs))*st;
for i:=0 to length(ln_rs)-1 do
ss:=ss+ln_rs[i];
ss:=(1/length(ln_rs))*ss;
for i:=0 to length(ln_rs)-1 do
sst:=sst+ln_t[i]*ln_rs[i];
sst:=(1/length(ln_rs))*sst;
for i:=0 to length(ln_rs)-1 do
st2:=st2+ln_t[i]*ln_t[i];
st2:=(1/length(ln_rs))*st2;
Herst:=(sst-st*ss)/(st2-st*st); //coefficient of approximal function
al:=ss-st*Herst;
Thanks everybody =)
P.S.
for tau:=nach to l do
There is L, not 1. And L is Length of X array. And L>nach always besides last step, when l=nach.
P.P.S.
It works, guys. But values are not right. And they go out from range. Maybe, there is mistake in algorithm. Or maybe I skiped some step.
Last Update
It's mystic, but i only changed method of calculating array Z and it started works correctly....
Thanks all =)
First thing I see:
nach := 3;
for tau := nach to l do //w
This counts up. And because nach>1, the body of this loop won't be executed.
If you expect to count down. Use the downto variant. To count down:
for tau := nach downto l do //w
Given that the main loop (for tau) iterates from nach to l, the first four SetLength calls should set the length of l - nach + 1 instead of l - nach.
Should the line
z[i]:=z[i]+y[j];
not be
z[i]:=z[i - 1]+y[j];
?
I'm working on a programming problem.
Note: This is not a student project. I am working on this for a new Quest for the website Try My Quest Dot Com, for which i am the admin.
Problem:
Jenny just started work as a programmer for Justine's Java Workshop. She is paid $10
an hour, with a few exceptions. She earns an extra $1.50 an hour for any part of a day where she works more than 8 hours, and an extra $2.50 an hour for hours beyond 40 in any one week. Also, she earns a 125% bonus for working on Saturday, and a 50% bonus for working on Sunday. The bonuses for Saturday and Sunday are computed based on the hours worked those days; they are not used to calculate any bonus for working more than 40 hours in a week. You'll be given the number of hours Jenny worked each day in a week (Sunday, Monday, etc ), and you need to compute her salary for the week. The input will be positive integers, less than or equal to 24. The output must be formatted with a dollar sign and rounded up to the nearest penny. For example, $2" and $2.136666" are wrong answers; the correct versions are $2.00" and $2.14", respectively.
Anyway, i am trying to write this in Delphi (No form project). I pass the program a command line argument - timecard.dat
input
0, 8, 8, 8, 8, 8, 0
0, 10, 10, 10, 10, 10, 0
0, 0, 8, 8, 8, 8, 8
0, 0, 0, 10, 10, 10, 10
10, 10, 10, 9, 9, 9, 9
Output
Output #1: $400.00
Output #2: $540.00
Output #3: $500.00
Output #4: $540.75
Output #5: $905.88
My Out put however is:
Output #1: $400.00
Output #2: $540.00
Output #3: $500.00
Output #4: $537.00
Output #5: $902.50
The last two output values of mine are different from the actual results. Not sure why, and the more i stare at the code, the less i see it
Can anyone tell me what i have done wrong?
program ACSL_Time_Cards;
{assumes Sunday = 1, Monday 3, etc}
uses
SysUtils,
Dialogs;
const
HourlyWage = 10.00;
OverEightWage = 1.50;
OverFortyWage = 2.50;
var
F: TextFile;
I, ArrayIndex: Integer;
WeeklyHours: Array[0..6] of Integer; //weekly hours
HourStr, LineStr: String;
TotalHours, TotalOverFortyHours, TotalOverEightHours, TotalSatHours, TotalSunHours: Integer;
TotalWages: Real;
begin
//initialize variables
TotalHours:= 0;
TotalOverEightHours:= 0;
TotalOverFortyHours:= 0;
TotalSatHours:= 0;
TotalSunHours:= 0;
TotalWages:= 0.00;
ArrayIndex:= 0;
//open file "timecard.dat" for input
if FileExists(ParamStr(1)) then
begin
AssignFile(F, ParamStr(1));
Reset(F);
//step through file and extract each line and store in hoursStr
while not EOF(F) do
begin
Readln(F, LineStr);
//step through hours string and fill Array with weekly hours
for I:= 1 to length(LineStr) do
begin
//if character is not a ',' then add it to hourStr
if LineStr[I] <> ',' then
HourStr:= HourStr + LineStr[I]
else
begin
//add HourStr to Array
WeeklyHours[ArrayIndex]:= StrToInt(HourStr);
//reset the variable
HourStr:= '';
//increment Variable
Inc(ArrayIndex);
end; //else
end; //for I:= 1 to length(HoursStr) do
//clean up by adding the last remaining one
WeeklyHours[ArrayIndex]:= StrToInt(HourStr);
//step through array and figure out overtime Daily and Weekly
for I:= Low(WeeklyHours) to High(WeeklyHours) do
begin
TotalHours:= TotalHours + WeeklyHours[I];
if WeeklyHours[I] > 8 then
TotalOverEightHours:= TotalOverEightHours + WeeklyHours[I]-8;
//get sunday hours
if I + 1 = 1 then
TotalSunHours:= TotalSunHours + WeeklyHours[I];
//get saturday hours
if I + 1 = 7 then
TotalSatHours:= TotalSatHours + WeeklyHours[I];
end;
//get total over 40 hours
if TotalHours > 40 then
TotalOverFortyHours:= TotalHours-40;
//compute Regular Hours
TotalWages:= TotalWages + TotalHours * 10.00;
//compute overtime hours
TotalWages:= TotalWages + TotalOverEightHours * 1.50;
TotalWages:= TotalWages + TotalOverFortyHours * 2.50;
//compute bonuses
TotalWages:= TotalWages + (TotalSatHours * 10.00) * 1.25;
TotalWages:= TotalWages + (TotalSunHours * 10.00) * 0.50;
ShowMessage('TotalWages: ' + FormatFloat('$0.00', TotalWages));
//reset variables
TotalWages:= 0.00;
TotalHours:= 0;
TotalOverEightHours:= 0;
TotalOverFortyHours:= 0;
TotalSatHours:= 0;
TotalSunHours:= 0;
HourStr:= '';
ArrayIndex:= 0;
end; //while not EOF(F) do
CloseFile(F);
end
else
ShowMessage('File does not exist!');
end.
I'm sure there are many ways that this could have been written better. I really am just interested in why my values different from the expected values. Thanks!
For a simple problem like this, you might want to write it out by hand and then see if your code follows the same steps you did.
For Output 4, the 125% bonus for Saturday is not including the $1.50 per hour extra after 8:
she should earn
Wed: $103 | $100 for 10 hours plus $3 for 2 hours over 8
Thu: $103 | $100 for 10 hours plus $3 for 2 hours over 8
Fri: $103 | $100 for 10 hours plus $3 for 2 hours over 8
Sat: $231.75 | ($100 for 10 hours, $3 for 2 hours over 8), $128.75 for 125% bonus
for a total of 540.75
The code would benefit from the I/O and the calculation being separated. You problems are with the calculation. I'd write it something like this:
uses
Math;
type
TDay = (
daySunday,
dayMonday,
dayTuesday,
dayWednesday,
dayThursday,
dayFriday,
daySaturday
);
TDayArray = array [TDay] of Integer;
function Wage(const Hours: TDayArray): Double;
const
BasicRate = 10.0;
DailyOvertimeRate = 1.5;
WeeklyOvertimeRate = 2.5;
DailyOvertimeThreshold = 8;
WeeklyOvertimeThreshold = 40;
DailyBonus: array [TDay] of Double = (1.5, 1.0, 1.0, 1.0, 1.0, 1.0, 2.25);
var
Day: TDay;
DailyOvertimeHours, WeeklyOvertimeHours, TotalHours: Double;
DailyPay: array [TDay] of Double;
begin
TotalHours := 0.0;
for Day := low(Day) to high(Day) do begin
TotalHours := TotalHours + Hours[Day];
DailyOvertimeHours := Max(Hours[Day]-DailyOvertimeThreshold, 0.0);
DailyPay[Day] := Hours[Day]*BasicRate;
DailyPay[Day] := DailyPay[Day] + DailyOvertimeHours*DailyOvertimeRate;
DailyPay[Day] := DailyPay[Day]*DailyBonus[Day];
end;
WeeklyOvertimeHours := Max(TotalHours-WeeklyOvertimeThreshold, 0.0);
Result := Sum(DailyPay) + WeeklyOvertimeHours*WeeklyOvertimeRate;
end;
This is still a little unpolished and I'm not very happy with the variable names for pay rates, overtime etc.
Once have such a utility function available, then putting it together with the rest of your program becomes a lot easier.
The biggest weakness in your current program is that everything is housed in one giant routine. Break it down into small pieces and you'll be able to verify those small pieces more readily than hunting for problems in a single large routine.
Find this by yourself by learning How to debug a Delphi program.
Pay atention to this parts:
Watches - you add a watch to track the values of program variables or expressions as you step over or trace into code.
Breakpoints - when pressing the F5 button or clicking on the left bar in your editor you can add a red line to your source. This line of source will have a breakpoint. When running the program, the execution will stop when it passes the source line. Now you can trace into your source by using some function keys.
I am using a multi-dimensional dynamic array in delphi and am trying to figure this out:
I have 2 seperate values for the first index and second index that are totally seperate of each other.
As new values come I want to grow the array if that new value is outside of either bound.
For new values x, y
I check:
if Length(List) < (x + 1) then
SetLength(List, x + 1);
if Length(List[0]) < (y + 1) then
SetLength(List, Length(List), y + 1);
Is this the correct way to do this or is there a better way to grow the array as needed?
It looks fine to me - if you change the last line to
SetLength(List, Length(List), y + 1);
I think you forgot to use the second index on the second dimension;
Your code should probably read like this :
if Length(List) < (x + 1) then
SetLength(List, x + 1);
if Length(List[x]) < (y + 1) then
SetLength(List[x], y + 1);
Note the use of 'x' as the first dimension index when growing the second dimension.
One caution though :
You should be aware of the fact that Delphi uses reference-counting on dynamic arrays too (just like how it's done with AnsiString).
Because of this, growing the array like above will work, but any other reference to it will still have the old copy of it!
The only way around this, is keeping track of these array's with one extra level of indirection - ie. : Use a pointer to the dynamic array (which is also a pointer in itself, but that's okay).
Also note that any of those 'external' pointers should be updated in any situation that the address of the dynamic array could change, as when growing/shrinking it using SetLength().
#PatrickvL:
Sorry, but that is just plain wrong. Your code does not even compile because it tries to set two dimensions for the single-dimensional element List[x]. (PatrickvL updated his code so this part of the answer is no longer valid.)
The following code demonstrates multidimensional array resizing.
program TestDimensions;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
List: array of array of integer;
begin
//set both dimensions
SetLength(List, 3, 2);
Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 3, Y = 2
//set main dimension to 4, keep subdimension untouched
SetLength(List, 4);
Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 4, Y = 2
//set subdimension to 3, keep main dimenstion untouched
SetLength(List, Length(List), 3);
Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 4, Y = 3
//all List[0]..List[3] have 3 elements
Writeln(Length(List[0]), Length(List[1]), Length(List[2]), Length(List[3])); //3333
//you can change subdimension for each List[] vector
SetLength(List[0], 1);
SetLength(List[3], 7);
//List is now a ragged array
Writeln(Length(List[0]), Length(List[1]), Length(List[2]), Length(List[3])); //1337
//this does not even compile because it tries to set dimension that does not exist!
// SetLength(List[0], Length(List[0]), 12);
Readln;
end.
The Delphi help also explains this quite nicely (Structured Types, Arrays).
Multidimensional Dynamic Arrays
To declare multidimensional dynamic arrays, use iterated array of ... constructions. For example,
type TMessageGrid = array of array of string;
var Msgs: TMessageGrid;
declares a two-dimensional array of strings. To instantiate this array, call SetLength with two integer arguments. For example, if I
and J are integer-valued variables,
SetLength(Msgs,I,J);
allocates an I-by-J array, and Msgs[0,0] denotes an element of that array.
You can create multidimensional dynamic arrays that are not rectangular. The first step is to call SetLength, passing it parameters for the first n dimensions of the array. For example,
var Ints: array of array of Integer;
SetLength(Ints,10);
allocates ten rows for Ints but no columns. Later, you can allocate the columns one at a time (giving them different lengths); for example
SetLength(Ints[2], 5);
makes the third column of Ints five integers long. At this point (even if the other columns haven't been allocated) you can assign values to the third column - for example, Ints[2,4] := 6.
The following example uses dynamic arrays (and the IntToStr function declared in the SysUtils unit) to create a triangular matrix of strings.
var
A : array of array of string;
I, J : Integer;
begin
SetLength(A, 10);
for I := Low(A) to High(A) do
begin
SetLength(A[I], I);
for J := Low(A[I]) to High(A[I]) do
A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' ';
end;
end;