Reducing decimal places in Delphi - 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.

Related

Delphi Roundto and FormatFloat Inconsistency

I'm getting a rounding oddity in Delphi 2010, where some numbers are rounding down in roundto, but up in formatfloat.
I'm entirely aware of binary representation of decimal numbers sometimes giving misleading results, but in that case I would expect formatfloat and roundto to give the same result.
I've also seen advice that this is the sort of thing "Currency" should be used for, but as you can see below, Currency and Double give the same results.
program testrounding;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,Math;
var d:Double;
c:Currency;
begin
d:=534.50;
c:=534.50;
writeln('Format: ' +formatfloat('0',d));
writeln('Roundto: '+formatfloat('0',roundto(d,0)));
writeln('C Format: ' +formatfloat('0',c));
writeln('C Roundto: '+formatfloat('0',roundto(c,0)));
readln;
end.
The results are as follows:
Format: 535
Roundto: 534
C Format: 535
C Roundto: 534
I've looked at Why is the result of RoundTo(87.285, -2) => 87.28 and the suggested remedies do not seem to apply.
First of all, we can remove Currency from the question, because the two functions that you use don't have Currency overloads. The value is converted to an IEEE754 floating point value and then follows the same path as your Double code.
Let's look at RoundTo first of all. It is quick to check, using the debugger, or an additional Writeln that RoundTo(d,0) = 534. Why is that?
Well, the documentation for RoundTo says:
Rounds a floating-point value to a specified digit or power of ten using "Banker's rounding".
Indeed in the implementation of RoundTo we see that the rounding mode is temporarily switched to TRoundingMode.rmNearest before being restored to its original value. The rounding mode only applies when the value is exactly half way between two integers. Which is precisely the case we have here.
So Banker's rounding applies. Which means that when the value is exactly half way between two integers, the rounding algorithm chooses the adjacent even integer.
So it makes sense that RoundTo(534.5,0) = 534, and equally you can check that RoundTo(535.5,0) = 536.
Understanding FormatFloat is quite a different matter. Quite frankly its behaviour is somewhat opaque. It performs an ad hoc rounding in code that differs for different platforms. For instance it is assembler on 32 bit Windows, but Pascal on 64 bit Windows. The overall approach appears to be to take the mantissa of the floating point value, convert it to an integer, convert that to text digits, and then perform the rounding based on those text digits. No respect is paid to the current rounding mode when the rounding is performed, and the algorithm appears to implement the round half away from zero policy. However, even that is not implemented robustly for all possible floating point values. It works correctly for your value, but for values with more digits in the mantissa the algorithm breaks down.
In fact it is fairly well known that the Delphi RTL routines for converting between floating point values and text are fundamentally broken by design. There are no routines in the Delphi RTL that can correctly convert from text to float, or from float to text. In fact, I have recently implemented my own conversion routines, that do this correctly, based on existing open source code used by other language runtimes. One of these days I will get around to publishing this code for use by others.
I'm not sure what your exact needs are, but if you are wishing to exert some control over rounding, then you can do so if you take charge of the rounding. Whilst RoundTo always uses Banker's rounding, you can instead use Round which uses the current rounding mode. This will allow you to perform the round using the rounding algorithm of your choice (by calling SetRoundMode), and then you can convert the rounded value to text. That's the key. Keep the value in an arithmetic type, perform the rounding, and only convert to text at the very last moment, after the correct rounding has been applied.
In this case, the value 534.5 is exactly representable in Double precision.
Looking into source code, reveals that the FormatFloat function rounds upwards if the last pending digit is 5 or more.
RoundTo uses the Banker's rounding, and rounds to nearest even number (534) in this case.

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.

Delphi 7 Sum of two numbers with decimals

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.

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.

Why does ReadLn not assign values to all my variables in Delphi?

When using Delphi's ReadLn to read values from a tab-delimited file into a series of variables, why do some of the variables not get assigned to appropriate value when I step through the debugger?
i.e.
x, y, z: Integer;
...
ReadLn(fh, x, y, z);
MessageBox(int2Str(y));
...
Only y has a value, x and z are 0 ...
Note: This was edited after Mason Wheeler's entirely valid answer
Readln will parse input as well as it can for the variable types you give it, but if your first one (name) is a string, it'll read everything up to the linebreak. If you want to load in a tab-delimited file, I'd use a TStringList and set the delimiter character to #9.
This is a symptom of a more general gotcha, in particular trying to debug the values of unused variables.
In Short: By default, the compiler optimises away unused variables
If when writing code incrementally, you decide to debug and find out, say, that the ReadLn procedure is reading in the variables correctly, you may find that the values are empty or 0. Unless the variables are used later in the code - which may not be the case if you are debugging as you write each line - the compiler appears to optimise them away.
I used ReadLn in the example since it may well be that you want to use data in the second column of a csv file and so have to create various throwaway variables that are not used. When checking the values of the throwaway variables, you then find that they do not contain what you expect!
In the above example you can force the debugger to load the vlaues by simply 'using' the variables later in the code, i.e.
x, y, z: Integer;
...
ReadLn(fh, x, y, z);
MessageBox(int2Str(y));
MessageBox(int2Str(x));
MessageBox(int2Str(z));
...
Now, mousover will reveal the values of y and z as well
The use of ReadLn() is unreliable in this example, because it will read to the first whitespace, add this to the first number, then to the second whitespace, add that, etc. You're doing a ReadLn, thus anything beyond the third integer on that line is ignored! And missing values default to zero.
If your numbers are prefixed with spaces, X would be the space, thus zero. Y would be the first number up to the tab delimiter. Z would be the second space in front of the second number, thus default zero.
To be honest, I only use ReadLn() to read a whole string from a textfile. With tab-delimited types I tend to use all kinds of other techniques, including using a stringlist.
ReadLn? hmmm (from memory) Was it expecting one line for each variable??? Really don't remember...

Resources