RE: Really strange problem, for very bright people
"Majoros, Endre" <[email protected]> Fri, 8 Aug 2003 12:23:57 +0200
| Newsgroups | gmane.comp.lang.delphi.programming |
|---|---|
| Message-ID | <[email protected]> |
Hi Steve,
I think it can come from the order of evaluation of the expression.
If you read the Delphi help for extended (it is actually not very helpful), you'll see a note on Currency type:
"Currency is a fixed-point data type that minimizes rounding errors in monetary calculations. It is stored as a scaled 64-bit integer with the four least-significant digits implicitly representing decimal places. When mixed with other real types in assignments and expressions, Currency values are automatically divided or multiplied by 10000."
So actually the Currency type is not a real floating point type, but it has fixed number of digits.
Floating-point (real) arithmetic is necessarily inexact even simple-seeming numbers like 1/3 or 0.2 cannot be represented exactly. That is why the "printed" value of a variable, or the output of a simple calculation, may show an inexact value - something like 1.199999997 or 1.200000003 where 1.2 or 1.20 is expected. Where exactness is appropriate, either use integral types only, or convert by Round, Trunc, etc. to integers.
Accuracy and resolution must not be confused. In the case of single and double the accuracy should approach the resolution; but for the highest resolution case, extended, the accuracy, while better than for double will be appreciably less than the resolution. Usually.
Note that, while A+B = B+A, it may be that A+B+C <> C+B+A, since that is a comparison of (A+B)+C & (C+B)+A which may round differently. In Javascript IEEE Doubles, X = [0.03+0.03+0.01, 0.01+0.03+0.03] gives [0.06999999999999999, 0.07].
Here is a snippet of a Turbo Pascal FAQ:
Q: What real numbers types are there? How do I use them?
A: I'll only give the very basics, since the information is
contained in your friendly manuals and this FAQ is not intended to
replace them! If you have Turbo Pascal 7.0 please see in the
Language Guide the item on Real Types on pages 28-29 and Chapter 14
on Using the 80x87. However, the five real types are
TYPE LOW HIGH DIGITS BYTES
real | 2.9e-39 1.7e38 | 11-12 | 6
single | 1.5e-45 3.4e38 | 7-8 | 4
double | 5.0e-324 1.7e308 | 15-16 | 8
extended | 3.4e-4932 1.1e4932 | 19-20 | 10
comp | 0.0, 1.0 9.2e18 | 19-20 | 8
A much better presentation of the table can be found at Dr. John
Stockton's http://www.merlyn.demon.co.uk/pas-real.htm#FloatTypes
You'll always have an access to the real type. Using the others will
require appropriate setting the {$N} and the {$E} compiler
directives. To get more information about them, read the current
file in the Turbo Pascal IDE (i.e. the editor), move the cursor on
the directives above, and press Ctrl-F1 to get the TP help. For the
first select from the list of three the item "$N: Numeric
Coprocessor Switch".
If you have a program where you have user the type real and wish
to increase the accuracy, you do not need to change every occurrence
of "real". A much quicker method is shown by the small example below
{$N+} { The Numeric Coprocessor Switch needed for access to four
additional real types: Single, Double, Extended, and Comp. }
{$E-} {The compiler links with smaller floating-point library. It
requires that the math coprocessor is available at run time. }
type real = double; { ... this is the trick! ...}
var a, b : real;
begin
a := 4.0; b := 7.0;
writeln (a/b);
end.
John, quite correctly, comments on 'type real = double': "I don't
like redefining a standard, though not reserved, identifier - too
confusing - and prone to error if using Units, since one must ensure
that it applies in every Unit as well." I continue: with this in
mind, use e.g.
{$N+,E+} { Use coprocessor emulation for a change, better
generality, slower code. }
var a, b : extended;
begin
a := 4.0; b := 7.0;
writeln (a/b);
end.
Also see http://www.merlyn.demon.co.uk/pas-real.htm#Float
Comments from Osmo Ronkanen: 1) "If you use $N+ and especially if
you use also $E+, you should not use the real type." 2) "One way is
to do:
{$ifopt n+}
type real=double;
{$endif}
That way it compiles on both $N+ and $N- with no compromises."
And here is a link to the IEEE standard for floating points:
http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
Endre
-----Original Message-----
From: Stephen Wood [mailto:[email protected]]
Sent: Friday, August 08, 2003 12:08 PM
To: '[email protected]'
Subject: RE: [Delphi] Really strange problem, for very bright people
Thanks Jeff,
What I can't understand is that the calculation actually works with the
other types (extended, double, etc) only if the order is changed, so
therefore rounding issues, and insignificant digits are not the problem,
because the calculation does work....but just in a different order.
And secondly, how is a developer supposed to understand in what order to
write the calculations, unless the bug actually manifests itself?
And thirdly, this calculation is used many times with different input
parameters and calculates correctly, but it seems that the bug only happens
when "certain" input values are used....really really weird...
But thanks anyway!!!
-----Original Message-----
From: Jeff Steinkamp - N7YG [mailto:[email protected]]
Sent: Friday 08 August 2003 09:53
To: [email protected]
Subject: RE: [Delphi] Really strange problem, for very bright people
Try this and see what happens
vary vCalc1,vCalc2,vCalc3 : real; //works with the single type also
vCalc11,vCalc21,vCalc31 : real;
vCalc111,vCalc211,vCalc311 : real;
begin
vCalc1 := (4.328247 * ( 33660 / 1000 ) * 1.06 * 1 * 1 * 1.5 * 1.035 );
vCalc11 := ( 1.5 * 1 * ( 33660 / 1000 ) * 4.328247 * 1.06 * 1.035 );
vcalc111 := vcalc1-vcalc11;
vCalc2 := (4.328247 * ( 33660 / 1000 ) * 1.06 * 1 * 1 * 1.5 * 1.035 );
vCalc21 := (4.328247 * 1.06 * 1.5 * 1 * ( 33660 / 1000 ) * 1.035 );
vcalc211 := vcalc2 - vcalc21;
vCalc3 := (4.328247 * ( 33660 / 1000 ) * 1.06 * 1 * 1 * 1.5 * 1.035 );
vcalc31 := (4.328247 * 1.06 * 1.035 * 1.5 * 1 * ( 33660 / 1000 ) );
vcalc311 := vcalc3 - vcalc31;
The reason you are not having problems with the Comp and Currency type
is because of rounding of the numbers. The anomoly you are seeing is a
floating point problem that has been around for years that I am aware
of. If you break the equation into smaller chucks it works much better,
but if you are looking for extremely small resolution this could be a
problem.
Jeff Steinkamp
> -----Original Message-----
> From: Stephen Wood [mailto:[email protected]]
> Sent: 08 August, 2003 00:00
> To: '[email protected]'
> Subject: [Delphi] Really strange problem, for very bright people
>
>
> Hi all,
>
> I'm looking for some really bright people to help with this
> one, because in
> my entire life, I've never seen something as strange as this.
>
> We have a calculation engine that does a whole whack of
> calculations...on we
> picked up a bug with it. We then stripped down the
> calculation to bare bones
> and were quite amazed at what we found....below is a code
> snippet to explain
> what's happening...
>
> var
> vCalc : extended;
>
> vCalc := (4.328247 * ( 33660 / 1000 ) * 1.06 * 1 * 1 * 1.5 *
> 1.035 ) - ( 1.5
> * 1 * ( 33660 / 1000 ) * 4.328247 * 1.06 * 1.035 );
>
> This gives an answer of 2.7755575616e-17
>
> Now do this....
>
> vCalc := (4.328247 * ( 33660 / 1000 ) * 1.06 * 1 * 1 * 1.5 *
> 1.035 ) - (
> 4.328247 * 1.06 * 1.5 * 1 * ( 33660 / 1000 ) * 1.035 );
>
> You'll notice that I just moved the 4.328247 and 1.06 to the
> front of the of
> the second brackets and you get an answer of 1.3877787808e-17
>
> Now try this...
>
> vCalc := (4.328247 * ( 33660 / 1000 ) * 1.06 * 1 * 1 * 1.5 *
> 1.035 ) - (
> 4.328247 * 1.06 * 1.035 * 1.5 * 1 * ( 33660 / 1000 ) );
>
> All I've done now is move the 1.035 after the 1.06 in the
> second brackets
> and I get an answer of 0 (which is actually the correct
> answer, which we
> expected, and which Excel gives us as well)
>
> Just moving the value around in a multiplication calculation produces
> different results....the different results are consistent with single,
> double and extended types, but with comp and currency types,
> the calculation
> is correct every time....
>
> Can anyone explain this?
>
> Thanks
> Steve
>
>
>
> [Non-text portions of this message have been removed]
>
>
> ------------------------ Yahoo! Groups Sponsor
> ---------------------~-->
> Buy Ink Cartridges or Refill Kits for Your HP, Epson, Canon or Lexmark
> Printer at Myinks.com. Free s/h on orders $50 or more to the
> US & Canada. http://www.c1tracking.com/l.asp?cid=5511
> http://us.click.yahoo.com/l.m7sD/LIdGAA/qnsNAA/i7folB/TM
> --------------------------------------------------------------
> -------~->
>
> CodeCoffer - new Delphi code protection Tool!
> http://www.delphicollection.com/public/CodeCoffer.htm
> ---------------------------------------------------------------
> Unsubscribe:[email protected]
> List owner:[email protected]
> ---------------------------------------------------------------
>
> Your use of Yahoo! Groups is subject to
> http://docs.yahoo.com/info/terms/
>
>
>
CodeCoffer - new Delphi code protection Tool!
http://www.delphicollection.com/public/CodeCoffer.htm
---------------------------------------------------------------
Unsubscribe:[email protected]
List owner:[email protected]
---------------------------------------------------------------
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
[Non-text portions of this message have been removed]
CodeCoffer - new Delphi code protection Tool!
http://www.delphicollection.com/public/CodeCoffer.htm
---------------------------------------------------------------
Unsubscribe:[email protected]
List owner:[email protected]
---------------------------------------------------------------
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
------------------------ Yahoo! Groups Sponsor ---------------------~-->
Buy Ink Cartridges or Refill Kits for Your HP, Epson, Canon or Lexmark
Printer at Myinks.com. Free s/h on orders $50 or more to the US & Canada. http://www.c1tracking.com/l.asp?cid=5511
http://us.click.yahoo.com/l.m7sD/LIdGAA/qnsNAA/i7folB/TM
---------------------------------------------------------------------~->
CodeCoffer - new Delphi code protection Tool!
http://www.delphicollection.com/public/CodeCoffer.htm
---------------------------------------------------------------
Unsubscribe:[email protected]
List owner:[email protected]
---------------------------------------------------------------
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/