Jump to content

Recommended Posts

Good Day,

 

var

a,b : Double

 

a:= 66,3333

b:= 1,5

c:= a* b ( Delphi shows  c:= 99,5,   actually c should be 99,49995 )

How can i get exact result ( 99,49995 ) ?

 

Thank You

Share this post


Link to post

How do you display the result? You can control the number of decimals displayed when converting a floating-point value from its internal binary (not decimal!) representation, but the exact syntax depends on the function you use (Write, WriteLn, Format, FormatFloat, FloatToStr, FloatToStrF etc. The run-time library has accumulated quite a number of such conversion functions over time. Oh, and the result of your multiplication is actually not exactly  99,49995 since the computer stores numbers as binary and not as decimal, and since it only has a limited number of bits available many decimal numbers cannot be stored without a small loss of precision. These errors accumulate over calculation steps...

Share this post


Link to post

Thank you so much Peter

 

I dont convert anything

 

My Code = 

a:= MyQuery.FieldByName('TOTAL').asFloat;    (which is 66,3333.-)

b:= MyQuery.FieldByName('RATIO').asFloat;   (Which is 1,50 );

c:= a * b;   // In Debug i see c as 99,50  instead of  99,4999 

MyTable.Edit;

MyTableBENF.asFloat := c;   // i was expecting to see in mytable's BENF field  99,49 not 99,50

(BENF field in firebird3 database is as Numeric(15,2)

(In Delphi my table's releated field's Currency proporties = True)

 

 

 

 

Share this post


Link to post
var
  a, b, c: Double;
begin
  try
    a := 66.3333;
    b := 1.5;
    c := a * b;
    WriteLn(FloatToStrF(c, ffFixed, 16, 5));
    ReadLn;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Output: 99,49995

Share this post


Link to post

Guys, I think the problem reported above is more related to the Database than to Delphi itself and its adventures!
We must remember that the numbers, as reported above, are stored binary, not decimal!
And, when you define a field of type NUMERIC/DECIMAL 15x2, then, we must remember the range of the smallest and largest value that can be stored in this field! For that, you can check the Database or Delphi documentation.

See the example using Firebird 4.02, I created 6 fields:

Quote

CREATE TABLE MYTABLENUMERIC (
     FNUMERIC15X2 NUMERIC(15,2),
     FNUMERIC15X3 NUMERIC(15,3),
     FDECIMAL15X2 DECIMAL(15,2),
     FDECIMAL15X3 DECIMAL(15,3),
     FNUMERIC15X5 NUMERIC(15,5),      <-------   try keep the "precision"
     FDECIMAL15X5 NUMERIC(15,5)       <-------   maybe not as you see on "precision storing"
);

and using the formula from the first post, see the results:

 

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  FDQuery1.Open;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  a, b, c: double;
begin
  a          := 66.3333;
  b          := 1.5;
  c          := a * b;
  Edit1.Text := c.ToString;
  //
  FDQuery1.Append;
  FDQuery1.Fields[0].AsFloat := c;
  FDQuery1.Fields[1].AsFloat := c;
  FDQuery1.Fields[2].AsFloat := c;
  FDQuery1.Fields[3].AsFloat := c;
  FDQuery1.Fields[4].AsFloat := c;
  FDQuery1.Fields[5].AsFloat := c;
  FDQuery1.Post;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FDConnection1.Close;
end;

end.

 

bds_OYPYUiwAZs.gif

 

NOTE Now, YOU can use "DisplayFormat" to show your value in another "MASK"  for example:  0.##,  ###,00   etc... but the "real value stored on database" is another of course!

Edited by programmerdelphi2k

Share this post


Link to post

Firebird/InterBase® converts the columns as follows:

 
Definition Data type Created
Decimal(1)-Decimal(4) Small Integer
Decimal(5)-Decimal(9) Integer
Decimal(10)-Decimal(18) Int (64)

Note that if a DECIMAL(5) data type is specified, it is actually possible to store a value as high as a DECIMAL(9) because Firebird/InterBase® uses the smallest available data type to hold the value. For a DECIMAL(5) column, this is an INTEGER, which can hold a value as high as a DECIMAL(9).

 

Enhancement in precision of calculations with NUMERIC/DECIMAL (Firebird 4.0)

Supported in IBExpert since version 2017.12.03.

Source: https://github.com/FirebirdSQL/firebird/blob/master/doc/sql.extensions/README.data_types

Function

Maximum precision of NUMERIC and DECIMAL data types is increased to 34 digits.

Author Alex Peshkoff <peshkoff@mail.ru>

Syntax rules

 
    NUMERIC ( P {, N} )
    DECIMAL ( P {, N} )
        where P is precision (P <= 34, was limited prior with 18 digits) and N is optional number
        of digits after decimal separator (as before).

Storage

128-bit, format according to IEEE 754.

Example(s)

 
    1. DECLARE VARIABLE VAR1 DECIMAL(25);
    2. CREATE TABLE TABLE1 (FIELD1 NUMERIC(34, 17));

Note(s)

Numerics with precision less than 19 digits use SMALLINT, INTEGER, BIGINT or DOUBLE PRECISION as base datatype depending upon number of digits and dialect. When precision is between 19 and 34 digits DECFLOAT(34) is used for it. Actual precision is always increased to 34 digits. For complex calculations such digits are casted (internally, in trivial way) to DECFLOAT(34) and the result of various math (log, exp, etc.) and aggregate functions using high precision numeric argument is DECFLOAT(34).

--------

more info in:    https://www.ibexpert.net/ibe/pmwiki.php?n=Doc.DefinitionNUMERICDECIMAL

 

Edited by programmerdelphi2k

Share this post


Link to post
5 hours ago, Henry Olive said:

var

a,b : Double

 

a:= 66,3333

b:= 1,5

c:= a* b

What language is this? It's not Delphi.

 

Also, your expectation is incorrect. This is what Python says the right answer is:

>>> 66.3333 * 1.5
99.49994999999998

I expect that if you showed your actual code, it would be clear what is going on.

Share this post


Link to post
21 minutes ago, programmerdelphi2k said:

I think the problem reported above is more related to the Database

Where in the question is a database mentioned?

Share this post


Link to post

And for those who are "blind" due to constant and innate bad temper...

  • FDQUERY ->> accesses a data source in a DATABASE!
3 hours ago, Henry Olive said:

(BENF field in firebird3 database is as Numeric(15,2)

 

3 hours ago, Henry Olive said:

My Code = 

a:= MyQuery.FieldByName('TOTAL').asFloat;    (which is 66,3333.-)

b:= MyQuery.FieldByName('RATIO').asFloat;   (Which is 1,50 );

c:= a * b;   // In Debug i see c as 99,50  instead of  99,4999 

MyTable.Edit;

Edited by programmerdelphi2k

Share this post


Link to post
14 hours ago, David Heffernan said:

Where in the question is a database mentioned?

OK, there seem to be two questions asked by @Henry Olive

 

The first one doesn't have any mention of a database, but has code that does not compile. The second question has database but we don't know what the values are. 

 

@Henry Olive you can't get a definitive answer unless we have precise details of what the data is. 

 

One thing we can say is that floating point multiplication is correct in Delphi. 

 

Edited by David Heffernan

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×