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
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
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.
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
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.
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
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.