If someone can explain it to me?

We encourage new members to introduce themselves here. Get to know one another and share your interests.
User avatar
softdevo@tiscali.it
Posts: 191
Joined: Wed Sep 30, 2015 1:30 pm

If someone can explain it to me?

Post by softdevo@tiscali.it »

For those who have not read the image correctly, here is the simplification of the code under discussion:
(As I said, the same code in another application gives the right result: 870)
LOCAL cOre AS STRING
LOCAL nNUORE AS System.Double
LOCAL nTOMIC AS System.Double

cOre := SELF:Gior:Text // "8,70"
nNUORE := Val(cOre) // 8.70
nTOMIC := (System.Double)(nNUORE*100,0) // 869.99999999999989 ERROR!!!!!!!!!!!!!!

Danilo
User avatar
softdevo@tiscali.it
Posts: 191
Joined: Wed Sep 30, 2015 1:30 pm

If someone can explain it to me?

Post by softdevo@tiscali.it »

excuse me

LOCAL cOre AS STRING
LOCAL nNUORE AS System.Double
LOCAL nTOMIC AS System.Double

cOre := SELF:Gior:Text // "8,70"
nNUORE := Val(cOre) // 8.70
nTOMIC := (System.Double)(nNUORE*100) // 869.99999999999989
User avatar
wriedmann
Posts: 3783
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

If someone can explain it to me?

Post by wriedmann »

Ciao Danilo,

if you put that value to a database field with 2 decimals, or display it using a picture, it is rounded to a correct value.

I have these issues in VO all the time, and therefore I'm using Round() a lot, other than setting SetFloatDelta() to 0.0001.
In .NET fortunately we have the "decimals" datatype, and AFAIK it is the datatype the X# runtime uses internally for decimal numbers.
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
User avatar
softdevo@tiscali.it
Posts: 191
Joined: Wed Sep 30, 2015 1:30 pm

If someone can explain it to me?

Post by softdevo@tiscali.it »

Thanks Wolfgang, since the number is always a whole I solved this

nTOMIC := (System.Double)Round(nNUORE*100,0) //(System.Double)(nNUORE*100) //

But the problem remains …
Danilo
User avatar
wriedmann
Posts: 3783
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

If someone can explain it to me?

Post by wriedmann »

Hi Danilo,
the problem is not a problem of VO or X#, but a problem in the Microsoft Floating Point Library, or better in the representation of float or double. The float or real8 datatype was never planned for exact calculations, unfortunately.
Use System.Decimal whenever possible.
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
User avatar
Chris
Posts: 4978
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

If someone can explain it to me?

Post by Chris »

Danilo, please try this code in VO, or any other language:

Code: Select all

FUNCTION Start() AS INT
LOCAL f1 AS REAL8
LOCAL f2 AS REAL8

SetFloatDelta(0)

f1 := 0.015
f1 := f1 + f1 + f1
f1 *= 10.0

f2 := 0.45
? f1==f2 , f1<f2 , f1>f2
	WAIT 
RETURN 0 
Similarly in c#:

Code: Select all

public class Program
{
	static void Main()
	{
		double f1;
		double f2;
		
		f1 = 0.015;
		f1 = f1 + f1 + f1;
		f1 *= 10.0;
		
		f2 = 0.45;
		System.Console.WriteLine(f1==f2);
		System.Console.WriteLine(f1<f2);
		System.Console.WriteLine(f1>f2);
	}
}
In both samples, you would expect f1 == f2 == 0.45, but both samples return FALSE for == and TRUE for <. This is because none of those values can be represented in binary accurately, there is some precision loss, and the more arithmetic you do with decimal numbers, the more precision is lost.

When you store 0.015 in the f1 var, the actual value stored is something like 0.0149999999791 or similar, because there is no way to represent 0.015 in binary notation that the REAL8, REAL4, FLOAT etc types use. Yes, when you see the value in the debugger or print it with a function, you will usually see 0.015, but this is because there is a runtime function used to print the value, and this is smart, knowing about the precision lost and converts 0.0149999999791 to 0.015 before displaying it. But after a number of calculations with float numbers, you end up with accumulated precision lost in each calculation, so the end result is slightly wrong, and this is why you see this strange value in the debugger sometimes and sometimes not.

For this reason, there is the Decimal type in .Net, which does not store values in binary format internally, but uses a decimal representation. This makes it much slower, but also has zero precision lost, 0.015 will always be 0.015 with this type.
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
User avatar
Chris
Posts: 4978
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

If someone can explain it to me?

Post by Chris »

Hi Wolfgang,
wriedmann wrote: In .NET fortunately we have the "decimals" datatype, and AFAIK it is the datatype the X# runtime uses internally for decimal numbers.
X# is working exactly as in VO:

REAL8 and FLOAT use 8 bytes for representing the stored value, in binary format. REAL8 is a synonym for the .Net type System.Double, FLOAT is a special class which again uses a System.Double and also includes formatting info as in VO.

REAL4 uses 4 bytes, in binary format again, it is a synonym for System.Single.

When you want to use the Decimal type, you need to specify it explicitly.
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
User avatar
softdevo@tiscali.it
Posts: 191
Joined: Wed Sep 30, 2015 1:30 pm

If someone can explain it to me?

Post by softdevo@tiscali.it »

Ok guys, thanks to everyone, everything is clear.
Now I ask if I use System.Decimal instead of System.Double in my calculation class for attendance management that makes thousands of operations on decimal numbers, will the slowness of the decimal be appreciable or irrelevant?
Danilo
User avatar
lumberjack
Posts: 729
Joined: Fri Sep 25, 2015 3:11 pm
Location: South Africa

If someone can explain it to me?

Post by lumberjack »

Danilo,
softdevo@tiscali.it wrote:Ok guys, thanks to everyone, everything is clear.
Now I ask if I use System.Decimal instead of System.Double in my calculation class for attendance management that makes thousands of operations on decimal numbers, will the slowness of the decimal be appreciable or irrelevant?
It all depends, will try to explain with a bad coding example:

Code: Select all

LOCAL x, y as <SomeFloatType>
x := 1.2 * (2.0 / 3.0) <rest of calculation>
WHILE ctr < 1000000 .AND. x <> 0.0
    IF (1.2 * (2.0 / 3.0) <rest of calculation>) < 345.34555
        y += 1.2 * (2.0 / 3.0) <rest of  calc>
        x := 1.2 * (2.0 / 3.0) <rest of change x positively>
    ELSE
        y -= 1.2 / (2.0 / 3.0) <whatever>
        x := 1.2 / (2.0 / 3.0) <rest of change x negatively>
    ENDIF
    ctr++
ENDDO
Think we get the idea, we heavily making use of floating point calculations and we end up with (2.0 / 3.0) that cannot be represented exactly, we cannot get past that, but we can minimize the impact:

Code: Select all

LOCAL x, y as <SomeFloatType>
LOCAL xneg, xpos AS <FloatType>
xneg := 1.2 / (2.0 / 3.0)
xpos := 1.2 * (2.0 / 3.0)
x := xpos <rest of calculation>
WHILE ctr < 1000000 .AND. x <> 0.0
    IF (x <rest of calculation>) < 345.34555
        y += xpos <rest of  calc>
        x := xpos <rest of change x positively>
    ELSE
        y -= xneg <whatever>
        x := xneg <rest of change x negatively>
    ENDIF
    ctr++
ENDDO
So yes it will have an impact, but you can minimize that impact that reduce the number of floating point arithmetic calculations. This is an extreme example but the impact will be reduced aka. speed up the process.

In a single non-looped actual implementation it should not distract the user experience. Try where possible to eliminate floating point bottlenecks.

Hope that helps,
______________________
Johan Nel
Boshof, South Africa
User avatar
Chris
Posts: 4978
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

If someone can explain it to me?

Post by Chris »

softdevo@tiscali.it wrote:Ok guys, thanks to everyone, everything is clear.
Now I ask if I use System.Decimal instead of System.Double in my calculation class for attendance management that makes thousands of operations on decimal numbers, will the slowness of the decimal be appreciable or irrelevant?
Danilo
Most probably the speed difference will be irrelevant, because usually in our apps it's other things that slow down performance (disk access, GUI updates etc) and not numeric calculations. Of course I would not use the Decimal type if I wanted to calculate fractals, but for regular calculations, let's say 1,000 or 10,000 numeric calculations per command the difference will be zero. But of course it's always better if you give it a try and see in practice what difference it makes, if any.
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
Post Reply