Delphi 7 Sum of two numbers with decimals - delphi

Beginner here :)
I am trying to make a Delphi application that requires user input and then adds and subtracts those variables.
I succeeded in creating the application and everything works fine except:
Cannot find the proper way to deal with numbers with decimals.
Example:
A,B,C,D,E,F: string;
A1,B1,C1,D1,E1,F1: integer:
I use InputBox to get the user inputs.
I store the inputs in string variables.
I convert the string variable to integer with A1 := strToint(A);
At the end, I want to: A1+B1-C1-D1-E1-F1
End everything works if the input is integer.
The problem arises if the user enter a number with decimals.
I have searched all over the place but could not find an answer to my problem.(Or I did not understood)
Anyone can please point me in the right direction?
Thank you.

You are trying to convert a string to a floating point value.
First of all you need to change your Integer variables to be of type Double. This will allow you to store values that are not integers.
Secondly you need a different function to perform the conversion. You should use TryStrToFloat. This attempts to convert from string to floating point. If the conversion succeeds the function returns True, otherwise it returns False. For example:
var
str: string;
value: Double;
....
if not TryStrToFloat(str, value) then
begin
// handle error in some appropriate way
end;
// do something with value

As the name suggests, StrToInt converts a numeric string into its integer equivalent. There is also the analagous StrToFloat function for handling floating point numbers.
Your variables are currently defined as integers. If you want to use real/decimal numbers you will need to use the Double type.
I recommend you consult the Delphi documentation for more information on this.

Related

Operation on Hexadecimal DELPHI

My application has to do operation on Hexadecimal values.
For example,
If the input given by user is '0010F750', then my application will tell you the user which is the nearest value (from some set of pre defined values) and will give next value by adding '0000E500'.
How we can perform Hexa Decimal operations Find nearest, Add, Subtract from DELPHI?
Performing operations on hexadecimal values does not really mean anything. Numbers are numbers. Hexadecimal is merely a representation using base 16.
All you need to do is convert these hex strings to integers and you can use standard arithmetic operations.
function HexStrToInt(const str: string): Integer;
begin
Result := StrToInt('$' + str);
end;
Add and subtract using + and -. Use IntToHex to express values as their hex representations.
Your application does not and cannot "do operation on Hexadecimal values". Rather, it operates on binary values stored in chunks of data organized as bytes.
What the USER sees and what the PROGRAM works with are two completely unrelated things.
The number one (1) in binary is 00000001, in hex is 01, in decimal is 1, and in ASCII has the hexadecimal value of 31. Try printing the value of Ord('1').
You need to convert the external representation of your data, in Hex, to an internal representation as an Integer. That's what David was pointing to earlier.
Then you'd need to apply your "rounding" to the numeric value, then convert it back to a Hex string for the user to see.
Search around for examples that let you implement a simple calculator and you'll understand better.

How to change the system shortdatetime format using delphi xe3

I am going to try and make the question as simple as possible.
How do i either convert the system date to a format i would like, and still keep it a date and not a string.
Or how do i get the system's date format, to adjust my dates accordingly.
When i call
FormatShortdateTime('d/M/yyyy',Date);
I get the correct date as string, but cannot convert it back to a Tdate and use it, then it clashes with the system date settings.
If i can get the system shortdate format the problem would be solved.
Update
The answer below refers to the original question that you asked. You've edited the question multiple times now to ask different questions. You really should not do that and it is a sign that you should spend more time understanding the problem before asking questions.
Even so, the final part of the answer, probably still contains the advice that you need. Namely to stop using conversion functions that rely on the global FormatSettings variable, and always use conversion functions that are passed format settings as a parameter.
The date values in your database are not stored in the format that you expect. This program:
{$APPTYPE CONSOLE}
uses
System.SysUtils;
var
fs: TFormatSettings;
begin
fs := TFormatSettings.Create;
fs.ShortDateFormat := 'd/M/yyyy';
Writeln(DateToStr(StrToDate('18/2/2014', fs)));
end.
produces the following output on my machine:
18/02/2014
I guess on your machine it would produce a different output because your short date format is different from mine. But the point is that the call to StrToDate succeeds.
Clearly the values stored in your database are not in the form you claim. Because you claim that the above code would lead to a date conversion error in the call to StrToDate.
Let's step back and look at the initial part of your question:
I would like to know how to convert dates without having the system date influence the software.
The code in the answer above gives you an example of how to do that. Modern versions of Delphi overload the date and time conversion functions. There are overloads that accept TFormatSettings parameters, and overloads without such a parameter. The TFormatSettings parameter is used to control the format used for the conversion. The overloads that do not receive such a parameter use the global FormatSettings instance declared in the SysUtils unit.
What you should do to avoid having the system settings influence your conversions is to only use conversion functions that accept a format settings parameter.
On the other hand, if you want the system settings to influence your conversions, then feel free to call the overloads that use the global format settings variable.
My code above illustrates both. The conversion from string to date requires a fixed format, not varying with local system settings. The conversion from date to string is designed to show a date using the prevailing local system settings.
I would advice creating own TFormatSettings variable
older delphi versions
var
fs: TFormatSettings;
begin
fs := TFormatSettings.Create;
GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, fs);
end.
This will create your own formatSettings (filled with system format) so you won't alter the default one.
Now what's important is that '/' in shortDateFormat will be replaced by dateSeparator so if you do this
fs.ShortDateFormat:='M/d/yyyy';
fs.dateSeparator:='?';
your input should be like this
strtodate('12?30?1899', fs);
or if other way around you will end up with string: '12?30?1899';
I think that your problems originate from that you don't ask what dateSeparator is used. That would lead to problems if what program expects is '30-12-1899' but he gets '30/12/1899' from you.

How do I avoid errors when converting strings to numbers if I don't know whether I have floats or integers?

I have stringgrid on delphi form and i am trying to divide values of one cell with value of another cell in another column.
But the problem is, stringgrid cells are populated with different types of numbers, so I am getting ConvertErrors.
For example the numbers in cells can look like
0.37 or 34 or 0.0013 or 0.00 or 0.35 or 30.65 or 45.9108 or 0.0307 or 6854.93.
In another words I never know is it going to be real, float, integer or any other kind of type in those cells.
I have looked everywhere on internet but no luck. Anyone any ideas. By the way I am not exactly Delphi expert. Thanks.
For each string, convert it first to a float value using StrToFloat function in SysUtils.pas . This should allow for any numerical type to be dealt with (unless you have something unusual like complex numbers). As you have some zero values in your list above you should also ensure that you check for divide by zero conditions as this will also potentially throw an exception.
SysUtils has many functions such as TryStrToFloat, TryStrToInt, TryStrToInt64 etc for this purpose. These functions accept a reference parameter (var parameter) for returning the converted value and function itself returns true if the conversion is successful.
If you are sure that the string has a valid number then you can check the input string to see if it has a decimal point before deciding which function to use.
Treat all the numbers as float. Use StrToFloat, divide the numbers, and then convert the result back to string with FloatToStr. If the result is an integer, no decimal point would be produced.

Delphi Unicode String Type Stored Directly at its Address (or "Unicode ShortString")

I want a string type that is Unicode and that stores the string directly at the adress of the variable, as is the case of the (Ansi-only) ShortString type.
I mean, if I declare a S: ShortString and let S := 'My String', then, at #S, I will find the length of the string (as one byte, so the string cannot contain more than 255 characters) followed by the ANSI-encoded string itself.
What I would like is a Unicode variant of this. That is, I want a string type such that, at #S, I will find a unsigned 32-bit integer (or a single byte would be enough, actually) containing the length of the string in bytes (or in characters, which is half the number of bytes) followed by the Unicode representation of the string. I have tried WideString, UnicodeString, and RawByteString, but they all appear only to store an adress at #S, and the actual string somewhere else (I guess this has do do with reference counting and such). Update: The most important reason for this is probably that it would be very problematic if sizeof(string) were variable.
I suspect that there is no built-in type to use, and that I have to come up with my own way of storing text the way I want (which actually is fun). Am I right?
Update
I will, among other things, need to use these strings in packed records. I also need manually to read/write these strings to files/the heap. I could live with fixed-size strings, such as <= 128 characters, and I could redesign the problem so it will work with null-terminated strings. But PChar will not work, for sizeof(PChar) = 1 - it's merely an address.
The approach I eventually settled for was to use a static array of bytes. I will post my implementation as a solution later today.
You're right. There is no exact analogue to ShortString that holds Unicode characters. There are lots of things that come close, including WideString, UnicodeString, and arrays of WideChar, but if you're not willing to revisit the way you intend to use the data type (make byte-for-byte copies in memory and in files while still being using them in all the contexts a string could be allowed), then none of Delphi's built-in types will work for you.
WideString fails because you insist that the string's length must exist at the address of the string variable, but WideString is a reference type; the only thing at its address is another address. Its length happens to be at the address held by the variable, minus four. That's subject to change, though, because all operations on that type are supposed to go through the API.
UnicodeString fails for that same reason, as well as because it's a reference-counted type; making a byte-for-byte copy of one breaks the reference counting, so you'll get memory leaks, invalid-pointer-operation exceptions, or more subtle heap corruption.
An array of WideChar can be copied without problems, but it doesn't keep track of its effective length, and it also doesn't act like a string very often. You can assign string literals to it and it will act like you called StrLCopy, but you can't assign string variables to it.
You could define a record that has a field for the length and another field for a character array. That would resolve the length issue, but it would still have all the rest of the shortcomings of an undecorated array.
If I were you, I'd simply use a built-in string type. Then I'd write functions to help transfer it between files, blocks of memory, and native variables. It's not that hard; probably much easier than trying to get operator overloading to work just right with a custom record type. Consider how much code you will write to load and store your data versus how much code you're going to write that uses your data structure like an ordinary string. You're going to write the data-persistence code once, but for the rest of the project's lifetime, you're going to be using those strings, and you're going to want them to look and act just like real strings. So use real strings. "Suffer" the inconvenience of manually producing the on-disk format you want, and gain the advantage of being able to use all the existing string library functions.
PChar should work like this, right? AFAIK, it's an array of chars stored right where you put it. Zero terminated, not sure how that works with Unicode Chars.
You actually have this in some way with the new unicode strings.
s as a pointer points to s[1] and the 4 bytes on the left contains the length.
But why not simply use Length(s)?
And for direct reading of the length from memory:
procedure TForm9.Button1Click(Sender: TObject);
var
s: string;
begin
s := 'hlkk ljhk jhto';
{$POINTERMATH ON}
Assert(Length(s) = (PInteger(s)-1)^);
//if you don't want POINTERMATH, replace by PInteger(Cardinal(s)-SizeOf(Integer))^
showmessage(IntToStr(length(s)));
end;
There's no Unicode version of ShortString. If you want to store unicode data inline inside an object instead of as a reference type, you can allocate a buffer:
var
buffer = array[0..255] of WideChar;
This has two disadvantages. 1, the size is fixed, and 2, the compiler doesn't recognize it as a string type.
The main problem here is #1: The fixed size. If you're going to declare an array inside of a larger object or record, the compiler needs to know how large it is in order to calculate the size of the object or record itself. For ShortString this wasn't a big problem, since they could only go up to 256 bytes (1/4 of a K) total, which isn't all that much. But if you want to use long strings that are addressed by a 32-bit integer, that makes the max size 4 GB. You can't put that inside of an object!
This, not the reference counting, is why long strings are implemented as reference types, whose inline size is always a constant sizeof(pointer). Then the compiler can put the string data inside a dynamic array and resize it to fit the current needs.
Why do you need to put something like this into a packed array? If I were to guess, I'd say this probably has something to do with serialization. If so, you're better off using a TStream and a normal Unicode string, and writing an integer (size) to the stream, and then the contents of the string. That turns out to be a lot more flexible than trying to stuff everything into a packed array.
The solution I eventually settled for is this (real-world sample - the string is, of course, the third member called "Ident"):
TASStructMemHeader = packed record
TotalSize: cardinal;
MemType: TASStructMemType;
Ident: packed array[0..63] of WideChar;
DataSize: cardinal;
procedure SetIdent(const AIdent: string);
function ReadIdent: string;
end;
where
function TASStructMemHeader.ReadIdent: string;
begin
result := WideCharLenToString(PWideChar(#(Ident[0])), length(Ident));
end;
procedure TASStructMemHeader.SetIdent(const AIdent: string);
var
i: Integer;
begin
if length(AIdent) > 63 then
raise Exception.Create('Too long structure identifier.');
FillChar(Ident[0], length(Ident) * sizeof(WideChar), 0);
Move(AIdent[1], Ident[0], length(AIdent) * sizeof(WideChar));
end;
But then I realized that the compiler really can interpret array[0..63] of WideChar as a string, so I could simply write
var
MyStr: string;
Ident := 'This is a sample string.';
MyStr := Ident;
Hence, after all, the answer given by Mason Wheeler above is actually the answer.

Reducing decimal places in Delphi

I am storing a list of numbers (as Double) in a text file, then reading them out again.
When I read them out of the text file however, the numbers are placed into the text box as 1.59993499 for example, instead of 1.6.
AssignFile(Pipe, 'EconomicData.data');
Reset(Pipe);
For i := 1 to 15
Do ReadLn(Pipe, SavedValue[i]);
CloseFile(Pipe);
Edit1.Text := FloatToStr(SavedValue[1]);
The text in Edit1.text, from the code above, would be 1.59999... instead of the 1.6 in the text file. How can i make it so the text box displays the original value (1.6)?
you can use the FormatFloat Function
var
d: double;
begin
d:=1.59993499 ;
Edit1.Text:=FormatFloat('0.0',d); //show 1.6
end;
Sorry, I wasn't sure whether it will suit your requirements, but my original answer was to use:
Format('%n', [SavedValue[1]]);
Just be careful when using floating points. If your going to be performing calculations using the values, then your better off using either a currency type or an integer and implying the decimal point prior to saving. As you have noticed, floating point values are approximations, and rounding errors are bound to eventually occur.
For instance, lets say you want to store tenths in your program (the 1.6), just create an integer variable and for all intensive purposes think of it as tenths. When you go to display the value, then use the following:
Format('%n',[SavedValue[1]/10]);
Currency is an integer type with an implied decimal of thousandths.

Resources