Handling (+Infinity) values

Recently, I discovered that topspeed allows infinity values (output of value that is divided by zero) to be saved on a record. I encountered this when I am converting topspeed files to sql file (mariadb/mysql via odbc connector) in which it will show an error and will not allow to save the record on sql. Now I want to know how detect infinity values in able for me to handle such errors. Tried the following but I already tested not working.

IF tpsfile:col20 = (+Infinity)
    sqlfile:col20 = 0
END
!other procedures map other columns from tps to sql file
ADD(sqlfile)

I detected this using MESSAGE(WHAT(tpsfile,20)) which shows below message
image

What is the type of field in the TPS file.

Is it REAL ?

If so then I suggest you define an 8-byte string over it and display the bit value. It might be easier to display it in hex.

That way you will know the value and can easily detect matching fields and substitute zero in your conversion.

hth

PlusInf64          STRING('<0,0,0,0,0,0,0F0h,07FH>')
PlusInfiniity64    REAL,OVER(PlusInf64)
MinusInf64         STRING('<0,0,0,0,0,0,0F0h,0FFH>')
MinusInfiniity64   REAL,OVER(MinusInf64)

Everything is easy with +/-Infinity because these values have very particular layout.

“Not a Number” +NaN and -NaN values can’t be represented in this way e. g. 0/0 Sqrt(-1) Log(-1) . So, I would suggest to define a function returning some code depending from the kind of REAL parameter, e.g.

Real:Zero     EQUATE(0)
REAL:Normal   EQUATE(1)
Real:PlusInf  EQUATE(2)
Real:MinusInf EQUATE(3)
Real:PlusNaN  EQUATE(4)
Real:MinusNaN EQUATE(5)
Real:BadFmt   EQUATE(255)

                MAP
                  ClassOfReal (REAL),BYTE   !<- Result is one of Real:* values
                END
1 Like

NB: the compiler generates the call to the Cla$realdistinct RTL function on comparison of float point values for equality and inequality. This function has been implemented in JPI times and has some logical errors. This function is unlikely handling +/-Infinity and +/-NaN values correctly. The suggested way to use a function that analyzes the passed values for special cases would be better solution.

1 Like

You could read more about binary representation of the special numbers here Double-precision floating-point format - Wikipedia

About “detecting” ± Infinity in a simple way you can test INSTRING(‘Infinity’,RealVariable,1,1) > 0 relying on current automatic real to string conversion, but I don’t see that behavior documented so it is risky.

If you just want those to be replaced with zero you could tame it with a big enough temporary decimal variable that, but how big would depend on the range of your stored values. Eg instead of sqlfile:col20 = tpsfile:col20 both REALs, do

TempDec DECIMAL(31,15)


TempDec = tpsfile:col20
sqlfile:col20 = TempDec

The only reference I can find in the help docs is

RANGE (set range limits)

If no RANGE is set, and the FROM attribute is not used, PROP:RangeHigh returns “+Infinity”, and PROP:RangeLow returns “-Infinity”. When using the CREATE statement to create a SPIN control, these values are intentionally reversed, so that PROP:RangeHigh and PROP:RangeLow must be explicitly set.

The quotes suggest it might be a string value thats accepted/returned, so an ANY might be a better data type to use.

I recently came across the “infinity” thing in some json. First I’d ever heard of it. It showed up in some TPSFix’d data. When transferred to json via jfiles, it was showing that text (quoted) instead of a non-quoted numeric value.

I am guessing that a function like @anon77170705 suggests would be more efficient than one utilizing instring, but I am unclear about what would constitute Real:BadFmt or how much code it would take to determine it.

1 Like

I took status codes from some my code that handles 80-bit float point values as well. There are invalid bit layouts for such numbers.

80-bit float point values are not supported directly in Clarion but the RTL uses them to increase the accuracy of calculationsю

2 Likes

Wow I didn’t know that! Thanks.

I’m on my phone and unable to test any code.

A quick read on NaN says by definition Real NaN “Equality” should always be False. But compilers (or optimizations) do not always get it right so you’re saying Cla$RealDistinct() may not be correct?

That the below message may not show “=False” ?

R Real

  R = Sqrt(-1) ! Should be NaN

  Message('NaN Test Sqrt -1  R=' & R & |
     Choose(R=R,'|=True ~nan','|=False is NaN') &|
     Choose(R=R+0,'|+0=True ~nan','|+0=False is NaN') &|
      ,'NaN Test')

The compilers do not test float point numbers for some particular values but explicit 0.

Yes, the Cla$realdistinct function and its variants for 32-bit and 80-bit float point parameters evaluates the proximity of numbers with negative exponent larger by absolute value than number of bits in mantissa incorrectly. For example, declare an ENTRY control in some WINDOW with the @E picture and a REAL variable as an USE variable. Set that variable to 0 before WINDOW is opened and try to enter value 1.0E-100 in ENTRY after opening. Cla$realdistinct considers values 0 and 1.0E-100 as equal and discards input.

Clarion’s SQRT invokes the C Library’s sqrt function. sqrt checks the argument for validity. If it’s negative, the DOMAIN error is set and the function returns 0.

Thread Drift so dont know if @CarlBarnes wants to hive this off to its own separate thread?

For Template parameter passing, I’ve had to build this into a #Validate

#OF('Real')
   #IF( Numeric(%ISTB3CodeGroupParameterListDefault) )
   #Error('Passed the NUMERIC(%Symbol) check but the value might still crash the IDE, Avoid using large REALs (below e-307 or above e+307).')
   #Return %True
   #Else
   #Error('Failed Numeric(%Symbol) check')
   #Return %False
   #EndIF

Do the templates use the same Cla$ functions?

[Edit]: I made a mistake confirming that I solved the problem.

How will I detect what kind of REAL data is the parameter passed? For now I have no idea since I am new to this concern regarding data types.

It’s need to break the passed float point number down to components: sign, biased exponent and mantissa. Then bit values of the exponent and the mantissa must be checked against the documented number layout.

I wrote my code in C++. In Clarion you need to declare an array/GROUP variable OVER the passed parameter, e.g.

BA BYTE,DIM(8),OVER(FltParam)

and then use bitwise operations (BSHIFT, BAND, etc.) for analysis of parts of the number.

1 Like