
12

I am having an issue with a simple floating point application. I am setting a variable to a specific value and immediately after I set it, it is not exactly what I set it to. Here's an example
Draw_GX_Min:=999.999;
Writeln(Draw_GX_Min:3:30);
The writeln results in 999.999000000000020000000000000000
Why is it not 999.999000000000000000000000000000 where did 0.00000000000002 come from?
Draw_GX_Min is defined as a Double. I don't need that much precision for any reason. I'm just trying to understand why it's not what I set it to.
The reason I noticed this is because I have some conditional statements like
If Draw_GX_Min<>99.999 then
Something....
And sometimes they works as expected, and sometimes not.
I realize I could do:
If round(Draw_GX_Min*1000)<>999999 then
Something
and it would work, but why do I need to do this when I explicitly set it to 999.999?
Does anyone know what is going on here that would be kind enough to explain it to me?
I suspect this has something to do with floating point, but I don't really understand what's happening.
Is there a better way to define my variable, perhaps defined as fixed decimal point instead of allowing it to float.... so that say all numbers from 999.99999 to 999.99999 are guaranteed to be represented accurately to 5 decimal places so that if I set one to 999.99999 it would actually be 999.99999 exactly? I would rather have less precision but have variables retain exactly what they are set to, not something close
Thanks
James
_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


On 8/21/2017 3:02 PM, James Richters wrote:
> I am having an issue with a simple floating point application. I am setting a variable to a specific value and immediately after I set it, it is not exactly what I set it to. Here's an example
>
> Draw_GX_Min:=999.999;
> Writeln(Draw_GX_Min:3:30);
>
> The writeln results in 999.999000000000020000000000000000
>
> Why is it not 999.999000000000000000000000000000 where did 0.00000000000002 come from?
>
Out of thin air... Well, kind of. Double floating point means 16 digits
of precision, so when you force a 30 digit precision output, anything
past 16 digits is random garbage, at best...
Ralf

This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


On 8/21/2017 3:34 PM, Daniel Franzini wrote:
> It might be the case (I didn't do the math) that 999.999 doesn't have
> an exact representation in IEEE754 doubleprecision format, so the
> best you get is an aproximation (a pretty good one, btw).
Just use WriteLn (Draw_GX_Min:3:16) and you get no mystery digits anymore...
In pretty much any programming language/compiler, if you print more
digits than the precision of the used variable defines, you will get
random numbers after the defined precision.
This is not something FreePascal specific, any C/C++ compiler for
example will do the same thing. People need to learn what limitations
come along with floating point variables/calculations...
Ralf

This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


Am 22.08.2017 00:02 schrieb "James Richters" <[hidden email]>:
The others already wrote about floating point precision, so I won't repeat that.
> The reason I noticed this is because I have some conditional statements like
> If Draw_GX_Min<>99.999 then
> Something....
*DON'T* compare floating point numbers like that. Instead use SameValue() from the Math unit which has an additional epsilon value (with a default value) that defines a lower and upper bound from your desired value to compare to.
Regards,
Sven
_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


 OriginalNachricht 
Von: Sven Barth via fpcpascal
Betreff: Re: [fpcpascal] Freepascal Floating Point Issue
Datum: 22.08.2017, 7:54 Uhr
An: FPCPascal users discussions
Cc: Sven Barth
Am 22.08.2017 00:02 schrieb "James Richters" <[hidden email]>:
The others already wrote about floating point precision, so I won't repeat that.
> The reason I noticed this is because I have some conditional statements like > If Draw_GX_Min<>99.999 then > Something....
*DON'T* compare floating point numbers like that. Instead use SameValue() from the Math unit which has an additional epsilon value (with a default value) that defines a lower and upper bound from your desired value to compare to.
Regards, Sven
_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


Hi James,
Its unlikely that 999.999 has an EXACT representation in floating point.
999.99900000000002 maybe the closest value at your chosen precision.
Extended type has more precision, but still probably won't be exact.
Regards,
Peter B
_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


Am 22.08.2017 18:11 schrieb "Peter" <[hidden email]>:
>
> Hi James,
>
> Its unlikely that 999.999 has an EXACT representation in floating point.
>
> 999.99900000000002 maybe the closest value at your chosen precision.
>
> Extended type has more precision, but still probably won't be exact.
Additionally Extended is not cross platform.
Regards,
Sven
_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


On 21/08/17 22:15, Ralf Quint wrote:
> On 8/21/2017 3:02 PM, James Richters wrote:> I am having an issue with a simple floating point application. I am setting a variable to a specific value and immediately after I set it, it is not exactly what I set it to. Here's an example>> Draw_GX_Min:=999.999;> Writeln(Draw_GX_Min:3:30);>> The writeln results in 999.999000000000020000000000000000 >> Why is it not 999.999000000000000000000000000000 where did 0.00000000000002 come from?>Out of thin air... Well, kind of. Double floating point means 16 digitsof precision, so when you force a 30 digit precision output, anythingpast 16 digits is random garbage, at best...
And in any event, that's probably much more precision than the GPU is
using to generate the final image :)

Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk
[Opinions above are the author's, not those of his employers or colleagues]
_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


On 8/22/2017 1:39 PM, Mark Morgan Lloyd wrote:
> On 21/08/17 22:15, Ralf Quint wrote:
>> On 8/21/2017 3:02 PM, James Richters wrote:> I am having an issue
>> with a simple floating point application. I am setting a variable to
>> a specific value and immediately after I set it, it is not exactly
>> what I set it to. Here's an example>> Draw_GX_Min:=999.999;>
>> Writeln(Draw_GX_Min:3:30);>> The writeln results in
>> 999.999000000000020000000000000000 >> Why is it not
>> 999.999000000000000000000000000000 where did 0.00000000000002 come
>> from?>Out of thin air... Well, kind of. Double floating point means
>> 16 digitsof precision, so when you force a 30 digit precision output,
>> anythingpast 16 digits is random garbage, at best...
>
> And in any event, that's probably much more precision than the GPU is
> using to generate the final image :)
>
Well, older GPUs (at least NVidia, pretty sure similar restrictions
apply to AMD) use(d) only 32bit "single" floats, giving a 7 digit
precision, though newer ones can also handle 64bit doubles. But there
are quite a few differences in how certain FP operations are handled on
those GPUs, which result in even doubles only having 14 (instead of 16)
digits of precision at best. So while NVidia keeps mentioning IEEE754,
their GPUs are in practice not 100% compliant.
As I mentioned before, if someone needs to work a lot with floating
point arithmetic, it really helps to get yourself acquainted to the way
those works and all the possible pitfalls.
Btw, anyone know about a BCD math implementation for Free Pascal, like
it used to be implemented in DR CBASIC? (those were the days... ;) )
Ralf

This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


On 8/22/2017 5:16 PM, Paul Nance wrote:
> Turbo Pascal also had a BCD unit.
Well, no, there was no unit, rather a version of Turbo Pascal 3.0x had a
version that natively used BCD math for "reals" instead of the 6byte
REAL type, just as there was a x87 version that used hardware x87 FP
(IEEE754) floats instead of software emulated ones. That was at a time
when the x87 processors where an addon to the basic CPU (8087 for the
8086/8088/80188, 80187 for the 808186, 80287 for 80286, 80387 for the
80386).
Ralf

This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


In reply to this post by Free Pascal  General mailing list
Thanks everyone for the explanation and solutions. I can work around it well enough now that I understand what’s happening, but I’m still curious if there is a way to define fixed point variables? In a C++ Project I was helping with recently, they had a way of defining a variable as having 2 places before the decimal and 30 places after? Since the decimal could never move (float) It ended up being much better defined. It’s like always moving the decimal over 30 places to the right, using integer math, then moving it back. I’m not sure if this was something the compiler did, or if maybe they had their own functions to do this… I had a difficult time following how things worked, but I do remember the fixed point variables. Anyway I thought I would just ask the question in case there is a way to define this in FreePascal It seems to me that if you know you never need more than a fixed number of places before and after the decimal, then moving the decimal over the maximum number of places, performing integer math, which would round to the nearest integer(and cut off the useless garbage), then moving the decimal back would mean a fixed amount of precision with the benefit that one could do things like exact conditionals and get the expected result James From: fpcpascal [mailto:[hidden email]] On Behalf Of Sven Barth via fpcpascal Sent: Tuesday, August 22, 2017 1:55 AM To: FPCPascal users discussions <[hidden email]> Cc: Sven Barth <[hidden email]> Subject: Re: [fpcpascal] Freepascal Floating Point Issue Am 22.08.2017 00:02 schrieb "James Richters" <[hidden email]>: The others already wrote about floating point precision, so I won't repeat that. > The reason I noticed this is because I have some conditional statements like > If Draw_GX_Min<>99.999 then > Something.... *DON'T* compare floating point numbers like that. Instead use SameValue() from the Math unit which has an additional epsilon value (with a default value) that defines a lower and upper bound from your desired value to compare to. Regards, Sven _______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


Am 24.08.2017 14:00 schrieb "James Richters" <[hidden email]>:
>
> Thanks everyone for the explanation and solutions. I can work around it well enough now that I understand what’s happening, but I’m still curious if there is a way to define fixed point variables? In a C++ Project I was helping with recently, they had a way of defining a variable as having 2 places before the decimal and 30 places after? Since the decimal could never move (float) It ended up being much better defined. It’s like always moving the decimal over 30 places to the right, using integer math, then moving it back. I’m not sure if this was something the compiler did, or if maybe they had their own functions to do this… I had a difficult time following how things worked, but I do remember the fixed point variables. Anyway I thought I would just ask the question in case there is a way to define this in FreePascal
>
They probably had a custom type with operator overloads and such for that which can be parameterized as a template with the amount of digits before and after the comma...
Somethings like that can be implemented in FPC as well, but the implementation would need to be done first at all ;)
Note: FPC (and Delphi) has a single fixed point type which is Currency. AFAIK it uses four digits after the comma and 28 in front of it.
Regards,
Sven
_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal


On 24/08/17 13:26, Sven Barth via fpcpascal wrote:
[...]
>
> Note: FPC (and Delphi) has a single fixed point type which is
> Currency. AFAIK it uses four digits after the comma and 28 in front
> of it.
>
> Regards, Sven
>
There was a project I remember, that I was told, for some e.g. tax purposes,
4 digits after the decimal point are not enough to round them properly...
That is because, the calculation of e.g. VAT has to work out both ways (total=net+VAT and
has to work out in every way, including when a bigger package is split into smaller units)
and 4 decimal digits are not always enough to ensure this (and the program had to work
internationally with all the different tax rules too) for arbitrarily large quantities, prices and tax bands.
I don't remember the exact details (it long time ago and couple of workplaces ago), of what they did,
but the team developing it (in D7) was pretty stressed...
l.
_______________________________________________
fpcpascal maillist  [hidden email]
http://lists.freepascal.org/cgibin/mailman/listinfo/fpcpascal

12
