xsharp.eu • float/double zero division
Page 1 of 2

float/double zero division

Posted: Sat Jul 27, 2019 5:41 pm
by Karl-Heinz
Hi Chris,

here are some test i made to check a float/double zero division. It seems that ? and AsString() causes the app to hang. There´s also a situation where floats and doubles behave different.

Code: Select all

FUNCTION Start() A VOID
LOCAL x := 3.00 AS FLOAT     //  -3.00
LOCAL y := 0.00 AS FLOAT  
LOCAL divResult AS FLOAT    

/*
LOCAL x := 3.00 AS double     //  -3.00
LOCAL y := 0.00 AS double  
LOCAL divResult AS double   
*/

	? "Start"
	?  
	divResult := x / y 
	? 

// 	? divResult  // the app hangs
//	? AsString ( divResult )  // the app hangs
//	VAR c := AsString ( divResult )  // the app hangs
	
	Console.WriteLine ( divResult )  // ok, +unendlich 
	
//	? AsString ( x / y  )  // the app hangs
	
//	? double.PositiveInfinity  // the app hangs
	? double.PositiveInfinity:ToString() // this works 	
	?
	Console.WriteLine ( double.PositiveInfinity )  // ok, +unendlich  
	
//  the comparison gives - correctly - true if a double is used, 
//  but false with a float.
    
    IF divResult == double.PositiveInfinity 
		? "PositiveInfinity"
		?
	ENDIF 
	
	// ok , true - no matter if floats or doubles are used	 
	// Seems to be the only way to detect infinity if floats are used.
	    
	IF Double.IsInfinity( divResult )
		divResult := 9.99
		
	ENDIF
	
	? divResult  // ok  9.99
		 
	?  
	
RETURN
regards
Karl-Heinz

float/double zero division

Posted: Sat Jul 27, 2019 6:07 pm
by Chris
Thanks Karl-Heinz, both problems confirmed, will take care of them!

float/double zero division

Posted: Thu Aug 22, 2019 7:06 am
by Karl-Heinz
Guys,

how do you handle a float zero division result ?

Code: Select all

fValue := 34.12 / 0  

? fValue         // +unendlich

? fValue * 3.34  // +unendlich

Of course, something like this causes a System.OverflowException.

Code: Select all

? Round ( fValue , 2 )  
the RDD system seems to take care of such divisions:

Code: Select all

fieldput ( 1 , fValue )  

? fieldget ( 1 )  //  shows correctly 0.00 
a workaround is to use a func like:

Code: Select all

FUNCTION FloatDivision ( f1 AS FLOAT , f2 AS FLOAT ) AS FLOAT
LOCAL fResult AS FLOAT

	fResult := f1 / f2 
	
	IF Double.IsInfinity( fResult )
		fResult := 0.00 
				
	ENDIF 
	
	RETURN fResult

 
what do you think ?
might a compiler enhancement take care of such zero divisions ?

regards
Karl-Heinz

float/double zero division

Posted: Thu Aug 22, 2019 8:13 am
by FFF
Karl-Heinz,
maybe i'm too much in holiday mode, but a division by 0 results certainly NOT in Zero. So, i don't want to see the result from your workaround, nor would i want to get silently 0.00 in my table, if the RDD indeed does as you describe.

float/double zero division

Posted: Thu Aug 22, 2019 9:07 am
by lumberjack
Karl,
FFF wrote:Karl-Heinz,
maybe i'm too much in holiday mode, but a division by 0 results certainly NOT in Zero. So, i don't want to see the result from your workaround, nor would i want to get silently 0.00 in my table, if the RDD indeed does as you describe.
I think this is already catered for in the compiler switches /ovf and /fovf, but I would say it is the wrong way around. Currently if not set, it silently replace with 0 / 0.0; Robert/Chris maybe need to give us a summary, since the Help indicates it is only with the Vulcan/VO dialects used. What is the handling in X# Core for overflows? I assume overflow exception raised?

I would rather prefer the standard to be to throw an exception and use the /ovf and /fovf to treat it as 0 if needed or handled it programatically.

I do have scenarios where due to mathematical algorithms I need a zero since working with very small number arithmetic, and sometimes difficult to emulate/test since it is almost impossible to create a Unit Test case for it. My oldest case was in the late 80's where some code originally developed in Fortran ran happily for 8 years when suddenly it just did not work in a specific scenario. Took us months to find the culprit, which in the end was somebody have entered details quite correctly, problem was his specific scenario calculated exactly an Internal Rate of Return (IRR) = 0 (take note this was still on a mainframe IBM, so no debugger). So yes we added a check, but needless to say that same code still is basically running unmodified today, and we have never experienced somebody with a scenario again resulting in IRR = 0.
Just my 2c.

float/double zero division

Posted: Thu Aug 22, 2019 11:38 am
by Chris
Hmm, looks like this is a bug, at least when overflow checking is enabled, then a division by (float) zero should throw an exception (at least in the VO dialect), same with what VO does. It already throws an exception for dividing by (integer) zero.

float/double zero division

Posted: Thu Aug 22, 2019 11:55 am
by Karl-Heinz
Hi Johan,

just to clarify: I´m using the VO-dialect and the used fValue is a float

Local fValue as float

such a float zero division doesn´t throw an exception. The return value is either +infinity or -infinity, and it doesn´t matter if the settings /ovf and /fovf are checked or unchecked. A double behaves the same, but if fValue is a decimal, the fValue assignment throws an System.InvalidCastException exception.

>> Currently if not set, it silently replace with 0 / 0.0

are you sure ?

regards
Karl-Heinz

float/double zero division

Posted: Thu Aug 22, 2019 1:09 pm
by Karl-Heinz
Guys,

i made a VO core test. The *only* compiler switch that´s checked is /vo8. If decimals are used i see a DivideByZero exception, otherwise +Infinity.

Code: Select all

#define __USE_DECIMAL__ 1

FUNCTION Start( ) AS VOID 
	
#IFDEF __USE_DECIMAL__	

LOCAL fValue AS decimal
LOCAL i AS decimal 

	? "Decimal" 
	?
	i := 0.00m

  fValue := 34.12m / i  
  
#ELSE

LOCAL fValue AS DOUBLE 
LOCAL i AS DOUBLE 

	? "Double"

	i := 0.00

  fValue := 34.12 / i  


#ENDIF   
  

 ? fValue  // +Infinity
  
RETURN 
regards
Karl-Heinz

float/double zero division

Posted: Thu Aug 22, 2019 1:25 pm
by lumberjack
Hi Karl-Heinz,
Karl-Heinz wrote: >> Currently if not set, it silently replace with 0 / 0.0
are you sure ?
No I am not sure, hence why I asked Robert/Chris to maybe shed some light. Unfortunately all my math calculations has to be done with exception testing, hence I cannot rely on a compiler setting, I need an exception when overflow takes place in my scenarios and investigate why it occurs.

As an example to show what I am working with, just 2 macro compiled codeblocks from one of my simulation environments:

Code: Select all

{|oM,nA,a| a:=oM:aPar, ;
          nA:=oM:nAge-oM:nTimeLag - oM:nShock, ;
          (a[1] + a[2]*log(oM:nSPH) + ;
          a[3]*(oM:nSPH/100)^2) * (1-exp(-nA/(a[4] + a[5]*log(oM:nSPH) + ;
          a[6]/oM:nSPH + a[7]*(oM:nSPH/100)^2)))^(a[8] + ;
          a[9]/oM:nSPH + a[10]*log(oM:nSPH) + a[11]*oM:nSPH)}
{|oM,a,nX,nI1,nI2| a:=oM:aPar, ;
          nX:=oM:nHt1/oM:nHgt, ;
          nI1:=iif(nX<=a[5],1,0), ;
          nI2:=iif(nX<=a[6],1,0), ;
          (1/0.408004710919776)*((a[2]/3)*nX^3 + ;
          (a[1]/2)*nX^2-(a[1]+a[2])*nX-(a[3]/3)*((a[5]-nX)^3*nI1-a[5]^3) - ;
          (a[4]/3)*((a[6]-nX)^3*nI2-a[6]^3)) }
All this is handled by one Equation class and a couple of wrapper Driver classes with the business logic in them...

float/double zero division

Posted: Thu Aug 22, 2019 3:03 pm
by Karl-Heinz
Hi Johan,

i give up :woohoo:

I do not envy anyone who needs to work with this source code at some point ;-)

regards
Karl-Heinz