strange malfunction with udt

General discussion for topics related to the FreeBASIC project or its community.
srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

strange malfunction with udt

Post by srvaldez »

I was benchmarking a program that overloads the arithmetic operators when I noticed that it wasn't working as expected

Code: Select all

' b() is a udt
For i = 1 To n
	If b(i) <> 0 Then
		Print Using "b(###) = "; i;
		Print b(i)
	End If
Next i
all the necessary conversion operators have been defined, the strange thing is that if I do If b(i) <> 0L Then it works but it doesn't work with # although the let and constructor are defined for double as well
some time ago I ran into another problem where static variables declared near the end of my program would not have the values that were assigned to them, there was no problem if the variables were initialized near the top
in this program I did the constructors and let's near the top with the necessary functions forward-declared, I wonder if that could be the cause of the problem
btw, no problem with version 1.09
could not conjure up a small example that would exhibit the problem
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: strange malfunction with udt

Post by fxm »

You could have at least provided the code of your UDT along with that of the associated constructors and operators.

For 'If b(i) <> 0 Then', the direct operator to overload in priority is obviously the '<>' operator !
Do not confuse the let operator (assignment) and the '=' operator (equality) or '<>' operator (inequality).
coderJeff
Site Admin
Posts: 4323
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: strange malfunction with udt

Post by coderJeff »

Yes, more details would help.

float equality comparisons (single / double) quite often are unreliable and should be used with care, but maybe that is not the case. Though can be affected by toolchain, backend, compiler optimizations, etc.

Most recent changes to fbc 1.10.0 affect structures returned by by value from functions (which would also include operators returning UDT's by value).

Code: Select all

type T
	fld as double '' or single
end type
declare function f() as T
Structures returned by value from functions might be returned in floating point registers, or integer registers, or both, or by a hidden pointer to the result.

Many previous versions of fbc got the ABI wrong. The exact method depends on platform, 32 versus 64 bit, tool chain, and backend.

Mixing newly compiled code with an older library may cause a problem.
Or using a tool chain we don't know about may cause a problem.
srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

Re: strange malfunction with udt

Post by srvaldez »

hello coderJeff and fxm :)
I implemented the <> operator only for udt <> udt, it always worked before because of automatic conversion
if I extend the <> operator to the other numeric types then there's no problem
but what intrigues me is that appending the suffix L to 0 made it work
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: strange malfunction with udt

Post by fxm »

srvaldez wrote: Jan 10, 2023 12:13 I implemented the <> operator only for udt <> udt, it always worked before because of automatic conversion

What automatic conversion ? :
With a Cast operator (from UDT type to numeric type), or/and a conversion constructor (from numeric type to UDT type) ?

What does it mean more precisely your:
it does not work

Again:
fxm wrote: Jan 10, 2023 6:14 You could have at least provided the code of your UDT along with that of the associated constructors and operators.
(we cannot reason more precisely without this one)
srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

Re: strange malfunction with udt

Post by srvaldez »

ok fxm, then tell me why the following works if there's no automatic conversion

Code: Select all

type udt
	as long n
	Declare Constructor ( )
	Declare Constructor ( Byref rhs As udt)
	Declare Constructor ( Byval rhs As Double )
	Declare Constructor ( Byref rhs As String )
	Declare Destructor ( )
	
	Declare Operator Let ( Byref rhs As udt )
	Declare Operator Let ( Byval rhs As Double )
	Declare Operator Let ( Byref rhs As String )
	
	Declare Operator Cast ( ) As Long
	Declare Operator Cast ( ) As Double
	Declare Operator Cast ( ) As String
end type

Constructor udt ( )
	this.n=0
End Constructor

Constructor udt ( Byref rhs As udt )
	this.n=rhs.n
End Constructor

Constructor udt ( Byval rhs As Double )
	this.n=clng( rhs )
End Constructor

Constructor udt ( Byref rhs As String )
	this.n=clng(rhs)
End Constructor

Operator udt.Let ( Byref rhs As udt )
	this.n=rhs.n
End Operator

Operator udt.let ( Byval rhs As double)
	this.n=clng( rhs )
End Operator

Operator udt.Let ( Byref rhs As string )
	this.n=clng(rhs)
End Operator

Operator udt.cast ( ) As Long
	Operator = this.n
End Operator

Operator udt.cast ( ) As Double
	Operator = cdbl(this.n)
End Operator

Operator udt.cast ( ) As String
	Operator = str(this.n)
End Operator

Operator <> ( Byref lhs As udt, Byref rhs As udt) As Long
	Operator = lhs.n<>rhs.n
End Operator

Destructor udt ( )
End Destructor

dim as udt m

m=3
print m<>"3"
print m<>"2"
sleep
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: strange malfunction with udt

Post by fxm »

With the following debug code, you can track the various calls to constructors, operators, destructor:

Code: Select all

type udt
	as long n
	Declare Constructor ( )
	Declare Constructor ( Byref rhs As udt)
	Declare Constructor ( Byval rhs As Double )
	Declare Constructor ( Byref rhs As String )
	Declare Destructor ( )
	
	Declare Operator Let ( Byref rhs As udt )
	Declare Operator Let ( Byval rhs As Double )
	Declare Operator Let ( Byref rhs As String )
	
	Declare Operator Cast ( ) As Long
	Declare Operator Cast ( ) As Double
	Declare Operator Cast ( ) As String
end type

Constructor udt ( )
    print "'Constructor udt ( )'"
    print @this
	this.n=0
End Constructor

Constructor udt ( Byref rhs As udt )
    print "'Constructor udt ( Byref rhs As udt )'"
    print @rhs, @this
	this.n=rhs.n
End Constructor

Constructor udt ( Byval rhs As Double )
    print "'Constructor udt ( Byval rhs As Double )'"
    print rhs, @this
	this.n=clng( rhs )
End Constructor

Constructor udt ( Byref rhs As String )
    print "'Constructor udt ( Byref rhs As String )'"
    print rhs, @this
	this.n=clng(rhs)
End Constructor

Operator udt.Let ( Byref rhs As udt )
    print "'Operator udt.Let ( Byref rhs As udt )'"
    print @rhs, @this
	this.n=rhs.n
End Operator

Operator udt.let ( Byval rhs As double)
    print "'Operator udt.let ( Byval rhs As double)'"
    print rhs, @this
	this.n=clng( rhs )
End Operator

Operator udt.Let ( Byref rhs As string )
    print "'Operator udt.Let ( Byref rhs As string )'"
    print rhs, @this
	this.n=clng(rhs)
End Operator

Operator udt.cast ( ) As Long
    print "'Operator udt.cast ( ) As Long'"
    print @this, this.n
	Operator = this.n
End Operator

Operator udt.cast ( ) As Double
    print "'Operator udt.cast ( ) As Double'"
    print @this, cdbl(this.n)
	Operator = cdbl(this.n)
End Operator

Operator udt.cast ( ) As String
    print "'Operator udt.cast ( ) As String'"
    print @this, str(this.n)
	Operator = str(this.n)
End Operator

Operator <> ( Byref lhs As udt, Byref rhs As udt) As Long
    print "'Operator <> ( Byref lhs As udt, Byref rhs As udt) As Long'"
    print @lhs, @rhs, lhs.n<>rhs.n
	Operator = lhs.n<>rhs.n
End Operator

Destructor udt ( )
    print "'Destructor udt ( )'"
    print @this
End Destructor

Scope
    dim as udt m
    print

    m=3
    print
    
    print m<>"3"
    print
    
    print m<>"2"
    print
End Scope

sleep
The 'cast' operator (from udt to string) is not called in that case because it exists a conversion constructor (from string to udt) plus a '<>' operator (udt<>udt).
If at least one of the last 2 cited is missing (conversion constructor or '<>' operator), then the 'cast' operator (from udt to string) will be used before using the pre-built '<>' operator between strings (only for fbc 1.10.0).
srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

Re: strange malfunction with udt

Post by srvaldez »

thanks fxm
srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

Re: strange malfunction with udt

Post by srvaldez »

@fxm, @coderJeff
I didn't want to post my code because it's in my bigfloat routines and people are probably sick of reading about it, but it seems that there's no other way to show the problem, my problem is that only b(1) is printed when compiling with FB 1.10.0 whether using the gcc or gas86 backend
I trimmed the code as much as possible

Code: Select all

Const NUMBER_OF_DIGITS = 50

Const NUMBER_OF_BITS   = NUMBER_OF_DIGITS*3.321928094887362

#If (NUMBER_OF_BITS Mod 32)<>0
	Const NUM_BITS = (NUMBER_OF_BITS\32+1)*32
#Else
	Const NUM_BITS = NUMBER_OF_BITS
#Endif

Const NUM_DWORDS    =   NUM_BITS\32
Const BIAS          =   1073741824 '2 ^ 30

' Error definitions

#Define DIVZ_ERR        1                    'Divide by zero
#Define EXPO_ERR        2                    'Exponent overflow error
#Define EXPU_ERR        3                    'Exponent underflow error

Type BigFloat_struct
	Declare Constructor ( )
	Declare Constructor ( Byref rhs As BigFloat_struct )
	Declare Destructor ( )
	Declare Operator Let ( Byref rhs As BigFloat_struct )
	As Short sign
	As Ulong  exponent
	union
		As Ulong  Ptr mantissa
		As Ushort Ptr wmantissa
	end union
End Type

Constructor BigFloat_struct ( )
	If this.mantissa<>0 Then
		Print "pointer is not 0"
		End(1)
	End If
	this.mantissa=Callocate((NUM_DWORDS +1), 4)
	If this.mantissa=0 Then
		Print "unable to allocate memory"
		End(4)
	End If
	this.sign=0
	this.exponent=0
End Constructor

Constructor BigFloat_struct ( Byref rhs As BigFloat_struct )
	If this.mantissa<>0 Then
		Print "pointer is not 0"
		End(1)
	End If
	this.mantissa=Callocate((NUM_DWORDS +1), 4)
	If this.mantissa=0 Then
		Print "unable to allocate memory"
		End(4)
	End If
	this.sign=rhs.sign
	this.exponent=rhs.exponent
	For i As Long=0 To NUM_DWORDS
		this.mantissa[i]=rhs.mantissa[i]
	Next
End Constructor

Operator BigFloat_struct.let ( Byref rhs As BigFloat_struct )
	this.sign=rhs.sign
	this.exponent=rhs.exponent
	For i As Long=0 To NUM_DWORDS
		this.mantissa[i]=rhs.mantissa[i]
	Next
End Operator

Destructor BigFloat_struct ( )
	If this.mantissa=0 Then
		Print "unable to de-allocate memory"
		End(-4)
	Else
		Deallocate(this.mantissa)
	End If
	this.mantissa=0
End Destructor

Type BigFloat
	Declare Constructor ( )
	Declare Constructor ( Byval rhs As Long )
	Declare Constructor ( Byval rhs As Double )
	Declare Constructor ( Byref rhs As String )
	Declare Constructor ( Byref rhs As BigFloat )
	Declare Destructor ( )
	
	Declare Operator Let ( Byval rhs As Long )
	Declare Operator Let ( Byval rhs As Single )
	Declare Operator Let ( Byval rhs As Double )
	Declare Operator Let ( Byref rhs As String )
	Declare Operator Let ( Byref rhs As BigFloat )
	Declare Operator Cast ( ) As String
	Declare Operator Cast ( ) As Long
	Declare Operator Cast ( ) As Double
	
	Declare Function toString( Byval places As Long=NUM_DWORDS*9.63 ) As String
	Declare Function toLong ( ) As Long
	Declare Function toDouble ( ) As Double

	BigNum As BigFloat_struct

End Type

Declare Function fpcmp(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As Long
Declare Function fpadd(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
Declare Function fpsub(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
Declare Function fpmul(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
Declare Function fpmul_si(Byref x As BigFloat_struct, Byval y As Long, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
Declare Function fpdiv_si(Byref num As BigFloat_struct, Byval den As Long, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
Declare Function fpdiv(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
Declare Function dbl2fp(Byval x As Double) As BigFloat_struct
Declare Function fp2dbl(Byref x As BigFloat_struct) As Double
Declare Function si2fp(Byval m As Long, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
Declare Function str2fp(Byref x As String) As BigFloat_struct
Declare Function fp2str(Byref zz As BigFloat_struct, Byval digits As Long=NUMBER_OF_DIGITS+8) As String
Declare Function fpfix( Byref num As BigFloat_struct, byref jj as long=0 ) As BigFloat_struct
Declare Function fpfrac( Byref num As BigFloat_struct ) As BigFloat_struct


Function Bigfloat.toString( Byval places As Long=NUM_DWORDS*9.63 ) As String
	Function = fp2str( this.BigNum, places )
End Function

Function Bigfloat.toLong ( ) As Long
	Dim As Double x
	x=fp2dbl(this.BigNum)
	Return Clng(x)
End Function


Function Bigfloat.toDouble ( ) As Double
	Function = fp2dbl(this.BigNum)
End Function

Constructor Bigfloat ( )
	this.BigNum=si2fp(0, NUM_DWORDS)
End Constructor

Constructor Bigfloat ( Byval rhs As Long )
	this.BigNum=si2fp( rhs, NUM_DWORDS )
End Constructor

Constructor Bigfloat ( Byref rhs As String )
	this.BigNum=str2fp( rhs )
End Constructor

Constructor Bigfloat ( Byref rhs As Bigfloat)
	this.BigNum.sign=rhs.BigNum.sign
	this.BigNum.exponent=rhs.BigNum.exponent
	For i As Long=0 To NUM_DWORDS
		this.BigNum.mantissa[i]=rhs.BigNum.mantissa[i]
	Next
End Constructor

Constructor Bigfloat ( Byval rhs As Double )
	this.BigNum=dbl2fp( rhs )
End Constructor

Operator Bigfloat.let ( Byref rhs As Bigfloat )
	this.BigNum.sign=rhs.BigNum.sign
	this.BigNum.exponent=rhs.BigNum.exponent
	For i As Long=0 To NUM_DWORDS
		this.BigNum.mantissa[i]=rhs.BigNum.mantissa[i]
	Next
End Operator

Operator Bigfloat.let ( Byval rhs As Long )
	this.BigNum=si2fp( rhs, NUM_DWORDS )
End Operator

Operator Bigfloat.let ( Byref rhs As String )
	this.BigNum=str2fp( rhs )
End Operator

Operator Bigfloat.Let ( Byval rhs As single )
	this.BigNum=dbl2fp( cdbl(rhs) )
End Operator

Operator Bigfloat.Let ( Byval rhs As Double )
	this.BigNum=dbl2fp( rhs )
End Operator

Operator Bigfloat.cast ( ) As String
	Operator = fp2str(this.BigNum)
End Operator

Operator Bigfloat.cast ( ) As Long
	Dim As Double x
	x=fp2dbl(this.BigNum)
	Operator = Clng(x)
End Operator

Operator Bigfloat.cast ( ) As Double
	Operator = fp2dbl(this.BigNum)
End Operator

Destructor Bigfloat ( )
End Destructor

Operator + ( Byref lhs As Bigfloat, Byval rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum= fpadd(lhs.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator + ( Byref lhs As Bigfloat, Byval rhs As Double ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=dbl2fp( rhs )
	result.BigNum= fpadd(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator + ( Byval lhs As Double, Byref rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=dbl2fp( lhs )
	result.BigNum= fpadd( result.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator + ( Byref lhs As Bigfloat, Byval rhs As Long ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=si2fp( rhs )
	result.BigNum= fpadd(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator + ( Byval lhs As Long, Byref rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=si2fp( lhs )
	result.BigNum= fpadd( result.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator + (Byref lhs As Bigfloat, Byref rhs As String) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=str2fp(rhs)
	result.BigNum= fpadd(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator - ( Byref rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result = rhs
	result.BigNum.sign = result.BigNum.sign Xor &h8000
	Operator = result
End Operator

Operator - ( Byref lhs As Bigfloat, Byval rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum= fpsub(lhs.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator - ( Byref lhs As Bigfloat, Byval rhs As Double ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=dbl2fp( rhs )
	result.BigNum= fpsub(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator - ( Byval lhs As Double, Byref rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=dbl2fp( lhs )
	result.BigNum= fpsub( result.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator - ( Byref lhs As Bigfloat, Byval rhs As Long ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=si2fp(rhs, NUM_DWORDS)
	result.BigNum= fpsub(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator - ( Byval lhs As Long, Byref rhs As Bigfloat  ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=si2fp(lhs, NUM_DWORDS)
	result.BigNum= fpsub(result.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator - (Byref lhs As Bigfloat, Byref rhs As String) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=str2fp(rhs)
	result.BigNum= fpsub(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator * ( Byref lhs As Bigfloat, Byval rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum= fpmul(lhs.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator * ( Byref lhs As Bigfloat, Byval rhs As Double ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=dbl2fp( rhs )
	result.BigNum= fpmul(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator * ( Byval lhs As Double, Byref rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=dbl2fp( lhs )
	result.BigNum= fpmul( result.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator * ( Byref lhs As Bigfloat, Byval rhs As Long ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=si2fp(rhs, NUM_DWORDS)
	result.BigNum= fpmul(result.BigNum, lhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator * ( Byval lhs As Long, Byref rhs As Bigfloat  ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=si2fp(lhs, NUM_DWORDS)
	result.BigNum= fpmul(result.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator * (Byref lhs As Bigfloat, Byref rhs As String) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=str2fp(rhs)
	result.BigNum= fpmul(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator / ( Byref lhs As Bigfloat, Byval rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum= fpdiv(lhs.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator / ( Byref lhs As Bigfloat, Byval rhs As Double ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=dbl2fp( rhs )
	result.BigNum= fpdiv(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator / ( Byval lhs As Double, Byref rhs As Bigfloat ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=dbl2fp( lhs )
	result.BigNum= fpdiv( result.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator / ( Byref lhs As Bigfloat, Byval rhs As Long ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=si2fp(rhs, NUM_DWORDS)
	result.BigNum= fpdiv(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator / ( Byval lhs As Long, Byref rhs As Bigfloat  ) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=si2fp(lhs, NUM_DWORDS)
	result.BigNum= fpdiv(result.BigNum, rhs.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator / (Byref lhs As Bigfloat, Byref rhs As String) As Bigfloat
	Dim As Bigfloat result
	result.BigNum=str2fp(rhs)
	result.BigNum= fpdiv(lhs.BigNum, result.BigNum, NUM_DWORDS)
	Operator = result
End Operator

Operator = ( Byref lhs As BigFloat, Byref rhs As BigFloat ) As Long
	Operator = fpcmp(lhs.BigNum, rhs.BigNum, NUM_DWORDS)=0
End Operator

Operator < ( Byref lhs As BigFloat, Byref rhs As BigFloat ) As Long
	Operator = fpcmp(lhs.BigNum, rhs.BigNum, NUM_DWORDS)<0
End Operator

Operator > ( Byref lhs As BigFloat, Byref rhs As BigFloat ) As Long
	Operator = fpcmp(lhs.BigNum, rhs.BigNum, NUM_DWORDS)>0
End Operator

Operator <= ( Byref lhs As BigFloat, Byref rhs As BigFloat ) As Long
	Operator = fpcmp(lhs.BigNum, rhs.BigNum, NUM_DWORDS)<=0
End Operator

Operator >= ( Byref lhs As BigFloat, Byref rhs As BigFloat ) As Long
	Operator = fpcmp(lhs.BigNum, rhs.BigNum, NUM_DWORDS)>=0
End Operator

Operator <> ( Byref lhs As BigFloat, Byref rhs As BigFloat ) As Long
	Operator = fpcmp(lhs.BigNum, rhs.BigNum, NUM_DWORDS)<>0
End Operator

Private Function log2_32(Byval value As Ulong) As Long
'https://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers
	Static tab32(0 To 31) As Const Long = {0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31}
	value Or= Culng(value Shr 1)
	value Or= Culng(value Shr 2)
	value Or= Culng(value Shr 4)
	value Or= Culng(value Shr 8)
	value Or= Culng(value Shr 16)
	Return tab32(Culng(Culng(value * &h07C4ACDD) Shr 27))
End Function

Function shl32(Byval n As Ulong, Byval k As Ubyte, Byref c As Ulong) As Ulong
	If k>0 And k<32 Then
		Dim As Ulong carry=n
		Dim As Ubyte k32=32-k
		Asm
			mov cl, [k32]
			Shr dword Ptr [carry], cl
			mov cl, [k]
			Shl dword Ptr [n], cl
		End Asm
		c=carry
	End If
	Return n
End Function

Function shr32(Byval n As Ulong, Byval k As Ubyte, Byref c As Ulong) As Ulong
	If k>0 And k<32 Then
		Dim As Ulong carry=n
		Dim As Ubyte k32=32-k
		Asm
			mov cl, [k32]
			Shl dword Ptr [carry], cl
			mov cl, [k]
			Shr dword Ptr [n], cl
		End Asm
		c=carry
	End If
	Return n
End Function

Sub shiftl(Byref fac1 As BigFloat_struct, Byval k As Long, Byval dwords As Long=NUM_DWORDS)
	If k>0 And k<32 Then
		Dim As Integer i
		Dim As Ulong n, carry, c=0
		Dim As Long k32=32-k
		For i=dwords To 0 Step -1
			n=fac1.mantissa[i]
			carry=n
			carry=Cast(Ulong, (carry Shr k32))
			n=Cast(Ulong, (n Shl k))
			fac1.mantissa[i]=n+c
			c=carry
		Next
	Elseif k=32 Then
		Dim As Long i
		For i=0 To dwords-1
			fac1.mantissa[i]=fac1.mantissa[i+1]
		Next
		fac1.mantissa[dwords]=0
	End If
End Sub

Sub shiftr(Byref fac1 As BigFloat_struct, Byval k As Long, Byval dwords As Long=NUM_DWORDS)
	If k>0 And k<32 Then
		Dim As Long i
		Dim As Ulong n, carry, c=0
		Dim As Long k32=32-k
		For i=0 To dwords
			n=fac1.mantissa[i]
			carry=n
			carry=Cast(Ulong, (carry Shl k32))
			n=Cast(Ulong, (n Shr k))   
			fac1.mantissa[i]=c+n
			c=carry
		Next
	Elseif k=32 Then
		Dim As Integer i
		For i=dwords To 1 Step -1
			fac1.mantissa[i]=fac1.mantissa[i-1]
		Next
		fac1.mantissa[0]=0
	End If
End Sub

Function fpcmp(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As Long
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
		Dim As Long i
		Dim As Longint c
		If x.sign < y.sign Then
			Return -1
		End If
		If x.sign > y.sign Then
			Return 1
		End If
		If x.exponent<y.exponent Then
			If x.sign=0 Then
				Return -1
			Else
				Return 1
			End If
		End If
		If x.exponent>y.exponent Then
			If x.sign=0 Then
				Return 1
			Else
				Return -1
			End If
		End If

		For i=0 To dwords
			c=Clngint(x.mantissa[i])-clngint(y.mantissa[i])
			If c<>0 Then Exit For
		Next
		If c=0 Then Return 0
		If c<0 Then
			If x.sign=0 Then
				Return -1
			Else
				Return 1
			End If
		End If
		If c>0 Then
			If x.sign=0 Then
				Return 1
			Else
				Return -1
			End If
		End If
End Function

Function NORM_FAC1(Byref fac1 As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As Integer
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	' normalize the number in fac1
	' all routines exit through this one.

	'see if the mantissa is all zeros.
	'if so, set the exponent and sign equal to 0.
	Dim As Long i,er=0,f=0
	dim as ulong ui
	For i=0 To dwords
		If fac1.mantissa[i]>0 Then f=1
	Next
	If f=0 Then
		fac1.exponent=0
		fac1.sign=0
		Exit Function
	End If

	While fac1.mantissa[0]=0
		shiftl(fac1, 32, dwords)
		fac1.exponent-=32
		If fac1.exponent=0 Then
			NORM_FAC1=EXPU_ERR
			Exit Function
		End If
	Wend
	'i=__builtin_clz(fac1.mantissa[0])-3
	ui=fac1.mantissa[0]
	asm
		bsr eax, dword ptr [ui]
		mov dword ptr [ui], eax
	end asm
	i=(31-ui) -3
	If i>0 Then
		shiftl(fac1, i, dwords)
		fac1.exponent-=i
	End If
	'if the highmost Bit in fac1_man is nonzero,
	'shift the mantissa right 1 Bit and
	'increment the exponent      
	If fac1.mantissa[0]>(&h1ffffffful)Then
		While fac1.mantissa[0]>&h1ffffffful
		shiftr(fac1, 1, dwords)
		fac1.exponent+=1
		Wend
	Elseif fac1.mantissa[0]<&h10000000ul Then
		/' the following will probably never be executed '/
		'now shift fac1_man 1 to the left until a
		'nonzero Bit appears in the next-to-highest
		'Bit of fac1_man.  decrement exponent for
		'each shift.

		While fac1.mantissa[0]<&h10000000ul
			shiftl(fac1, 1, dwords)
			fac1.exponent-=1
		Wend
	End If

	'check for overflow/underflow
	If fac1.exponent<0 Then
	?"NORM_FAC1 fac1.exponent<0"
	NORM_FAC1=EXPO_ERR
	End If
End Function

Function si2fp(Byval m As Long, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	Dim As BigFloat_struct fac1
	Dim As Long n=Abs(m)

	If m=0 Then
		Return fac1
	End If

	fac1.mantissa[0]=n
	NORM_FAC1(fac1, NUM_DWORDS)
	fac1.exponent=log2_32(n)+BIAS+1   
	If m<0 Then
		fac1.sign=&H8000
	Else
		fac1.sign=0
	End If
	Return fac1
End Function

Function ui2fp(Byval m As Ulong, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	Dim As BigFloat_struct fac1

	If m=0 Then
		Return fac1
	End If

	fac1.mantissa[0]=m
	NORM_FAC1(fac1, NUM_DWORDS)
	fac1.exponent=log2_32(m)+BIAS+1   
	Return fac1
End Function

Sub fpadd_aux(Byref fac1 As BigFloat_struct, Byref fac2 As BigFloat_struct, Byval dwords As Long=NUM_DWORDS)
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	Dim As Long c
	Dim As Integer i
	Dim As Longint v

	c=0
	For i=dwords To 1 Step -1
		v=Clngint(fac2.mantissa[i])+Clngint(fac1.mantissa[i])+c
		If v>(&h100000000ull-1) Then
			v=v-&h100000000ull
			c=1
		Else
			c=0
		End If
		fac1.mantissa[i]=v
	Next
	v=Clngint(fac1.mantissa[0])+Clngint(fac2.mantissa[0])+c
	fac1.mantissa[0]=v
	NORM_FAC1(fac1, dwords)

End Sub

Sub fpsub_aux(Byref fac1 As BigFloat_struct, Byref fac2 As BigFloat_struct, Byval dwords As Long=NUM_DWORDS)
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	Dim As Long c
	Dim As Integer i
	Dim As Longint v
	c=0
	For i=dwords To 1 Step -1
		v=Clngint(fac1.mantissa[i])-clngint(fac2.mantissa[i])-c
		If v<0 Then
			v=v+&h100000000ull
			c=1
		Else
			c=0
		End If
		fac1.mantissa[i]=v
	Next
	v=Clngint(fac1.mantissa[0])-clngint(fac2.mantissa[0])-c
	fac1.mantissa[0]=v
	NORM_FAC1(fac1, dwords)
End Sub

Function fpadd(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS

	Dim As BigFloat_struct fac1,fac2
	Dim As Long i, t, c, xsign, ysign

	xsign=x.sign:x.sign=0
	ysign=y.sign:y.sign=0
	c=fpcmp(x, y, dwords)

	x.sign=xsign
	y.sign=ysign
	If c<0 Then
		fac1=y
		fac2=x
	Else
		fac1=x
		fac2=y
	End If
	t=fac1.exponent-fac2.exponent

	If t<(NUM_BITS+32) Then
		'The difference between the two
		'exponents indicate how many times
		'we have to multiply the mantissa
		'of FAC2 by 10 (i.e., shift it right 1 place).
		'If we have to shift more times than
		'we have dwords, the result is already in FAC1.

		If t>0 And t<(NUM_BITS+32) Then 'shift

			i=t\32
			While i>0
				shiftr(fac2, 32, dwords)
				t-=32
				i-=1
			Wend
			'While t>0

			If t>0 Then   shiftr(fac2, t, dwords)
				't-=1
				'Wend
			End If
			'See if the signs of the two numbers
			'are the same.  If so, add; if not, subtract.
			If fac1.sign=fac2.sign Then 'add
				fpadd_aux(fac1,fac2, dwords)
			Else
				fpsub_aux(fac1,fac2, dwords)
			End If
	Endif
	'NORM_FAC1(fac1, dwords)
	Return fac1
End Function

Function fpsub(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	Dim As BigFloat_struct fac1,fac2
	Dim As Long s
	fac1=x
	fac2=y
	fac2.sign=fac2.sign Xor &h8000
	fac1=fpadd(fac1,fac2, dwords)
	Return fac1
End Function

Function fpmul(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	Dim As BigFloat_struct fac1,fac2
	Dim As Integer i, j, ex, er, den, num
	Dim As Ulongint digit, carry, prod ', tmp
	Dim As Ulong  fac3(0 To 2*dwords+1)

	fac1=x
	fac2=y
	'check exponents.  if either is zero,
	'the result is zero
	If fac1.exponent=0 Or fac2.exponent=0 Then 'result is zero...clear fac1.
		fac1.sign=0
		fac1.exponent=0
		For i=0 To dwords
			fac1.mantissa[i]=0
		Next
		'NORM_FAC1(fac1)
		Return fac1
	Else

		If ex<0 Then
			er=EXPO_ERR
			Return fac1 'Exit Function
		End If

		'clear fac3 mantissa
		For i=0 To dwords
			fac3(i)=0
		Next

		den=dwords
		While fac2.mantissa[den]=0
			den-=1
		Wend
		num=dwords
		While fac1.mantissa[num]=0
			num-=1
		Wend

		If num<den Then
			Swap fac1, fac2
			'fac1=y
			'fac2=x         
			Swap den, num
		End If

		For j=den To 0 Step -1
			carry=0
			digit=fac2.mantissa[j]
			For i=num To 0 Step -1
				prod=fac3(i+j+1)+digit*fac1.mantissa[i]+carry
				/'tmp=fac1.mantissa[i]
				If __builtin_umulll_overflow (digit, tmp, prod) Then Print "mul overflow"
				tmp=fac3(i+j+1)
				If __builtin_uaddll_overflow (tmp, prod, prod) Then Print "add overflow"
				If __builtin_uaddll_overflow (carry, prod, prod) Then Print "add overflow"'/
				carry=prod   Shr 32'\&H100000000
				fac3(i+j+1)=prod '(prod mod &H100000000)
			Next

			fac3(j)=carry
		Next

		For i=0 To dwords
			fac1.mantissa[i]=fac3(i)
		Next      

	End If
	'now determine exponent of result.
	'as you do...watch for overflow.
	'ex=fac2.exponent-BIAS+fac1.exponent
	'fac1.exponent=ex

	ex=(fac2.exponent And &h7FFFFFFFul)-BIAS+1
	ex=ex+(fac1.exponent And &h7FFFFFFFul)-BIAS+1
	fac1.exponent=ex+BIAS+1

	'determine the sign of the product
	fac1.sign=fac1.sign Xor fac2.sign
	NORM_FAC1(fac1, dwords)
	Return fac1
End Function

Function fpmul_si(Byref x As BigFloat_struct, Byval y As Long, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
    Dim As BigFloat_struct fac1,fac2
    Dim As Integer count, ex, er, i, j
    Dim As Long n, v, c, num
    Dim As Longint carry, digit, prod, value
    fac1=x
    digit=Abs(y)
    If digit>&h7fffffff Then
		fac2=si2fp(y, dwords)
		fac1=fpmul(fac1, fac2, dwords)
		Return fac1
	End If
    'check exponents.  if either is zero,
    'the result is zero
    If fac1.exponent=0 Or y=0 Then 'result is zero...clear fac1.
        fac1.sign=0
        fac1.exponent=0
        For count=0 To dwords
            fac1.mantissa[count]=0
        Next
        NORM_FAC1(fac1, dwords)
        Return fac1
    Else
		If digit=1 Then
			If y<0 Then
				fac1.sign=fac1.sign Xor &h8000
			End If
			Return fac1
		End If
        'now determine exponent of result.
        'as you do...watch for overflow.

        If ex<0 Then
            er=EXPO_ERR
            Return fac1 'Exit Function
        End If
		num=dwords
		While fac1.mantissa[num]=0
			num-=1
		Wend        
		carry=0
			
		For i=num To 0 Step -1
			prod=digit*fac1.mantissa[i] +carry
			value=(prod Mod &h100000000)'+carry
			fac1.mantissa[i]=value
			carry=prod\&h100000000
		Next

		n=carry
'		i=__builtin_clz(n)
	asm
		bsr eax, dword ptr [n]
		mov dword ptr [i], eax
	end asm
	i=(31-i)
		shiftr(fac1, (32-i)+3)
		fac1.exponent+=(32-i+3)
		n=shl32(n, i-3,c)
		fac1.mantissa[0]+=n
    End If

    NORM_FAC1(fac1, dwords)

    If y<0 Then
		fac1.sign=fac1.sign Xor &h8000
	End If
    Return fac1
End Function

Function fpmul_ui(Byref x As BigFloat_struct, Byval y As Ulong, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
    Dim As BigFloat_struct fac1,fac2
    Dim As Integer count, ex, er, i, j
    Dim As Ulong n, v, c, num
    Dim As Ulongint carry, digit, prod, value
    fac1=x
    digit=Abs(y)
    If digit>&hfffffffful Then
		fac2=si2fp(y, dwords)
		fac1=fpmul(fac1, fac2, dwords)
		Return fac1
	End If
    'check exponents.  if either is zero,
    'the result is zero
    If fac1.exponent=0 Or y=0 Then 'result is zero...clear fac1.
        fac1.sign=0
        fac1.exponent=0
        For count=0 To dwords
            fac1.mantissa[count]=0
        Next
        NORM_FAC1(fac1, dwords)
        Return fac1
    Else
		If digit=1 Then
			Return fac1
		End If
        'now determine exponent of result.
        'as you do...watch for overflow.

        If ex<0 Then
            er=EXPO_ERR
            Return fac1 'Exit Function
        End If
		num=dwords
		While fac1.mantissa[num]=0
			num-=1
		Wend        
		carry=0
			
		For i=num To 0 Step -1
			prod=digit*fac1.mantissa[i] +carry
			value=(prod Mod &h100000000)'+carry
			fac1.mantissa[i]=value
			carry=prod\&h100000000
		Next

		n=carry
		'i=__builtin_clz(n)
	asm
		bsr eax, dword ptr [n]
		mov dword ptr [i], eax
	end asm
	i=(31-i)
		shiftr(fac1, (32-i)+3)
		fac1.exponent+=(32-i+3)
		n=shl32(n, i-3,c)
		fac1.mantissa[0]+=n
    End If

    NORM_FAC1(fac1, dwords)

    Return fac1
End Function

Function fpdiv_si(Byref num As BigFloat_struct, Byval den As Long, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	Dim As BigFloat_struct fac1
	Dim As Ulongint carry, remder=0
	Dim As Longint i, divisor
	Dim As Longint quotient
	Dim As Long j

	divisor=Abs(den)
	fac1=num
	If divisor=1 Then
		Return fac1
	End If
	If divisor = 0 Then
		Print "error: divisor = 0"
		Return fac1 'Exit function
	End If
	If divisor>2147483647 Then
		Print "error: divisor too large"
		Return fac1 'Exit function
	End If

	For i = 0 To dwords
		quotient = fac1.mantissa[i] + remder * &h100000000ull
		remder = quotient Mod divisor
		fac1.mantissa[i]=quotient \ divisor
	Next
	quotient = remder * &h100000000ull
	quotient=quotient \ divisor
	carry=fac1.mantissa[0]
	'j=__builtin_clz(fac1.mantissa[0])-3
	j=fac1.mantissa[0]
	asm
		bsr eax, dword ptr [j]
		mov dword ptr [j], eax
	end asm
	j=(31-j)-3
	If j>0 Then
		shiftl(fac1, j, dwords)
		fac1.exponent-=j
	End If

	While fac1.mantissa[0]>(&h1ffffffful)
		shiftr(fac1, 1, dwords)
		fac1.exponent+=1
	Wend
	NORM_FAC1(fac1)
	If den<0 Then
	fac1.sign=fac1.sign Xor &h8000
	End If
	Return fac1
End Function


Function fpdiv(Byref x As BigFloat_struct, Byref y As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS

	Dim As BigFloat_struct fac1, fac2, one
	Dim As Integer i, er, is_power_of_two
	Dim As Short sign

	fac1=x
	fac2=y

	one.exponent=(BIAS+1)
	one.mantissa[0]=&h10000000ul
	one=ui2fp(1)
	sign=fac2.sign
	fac2.sign=0
	If fpcmp(fac2, one)=0 Then
		fac1.sign=fac1.sign xor y.sign
		Return fac1
	Else
		fac2.sign=sign
	End If
	If fac2.exponent=0 Then ' if fac2 = 0, return
		' a divide-by-zero error and
		' bail out.
		fac1.mantissa[i]=&H1FFFFFFFul
		For i=1 To dwords
			fac1.mantissa[i]=&HFFFFFFFFul
		Next
		fac1.exponent=&HFFFFF+BIAS+1
		er=DIVZ_ERR
		Return fac1
	Elseif fac1.exponent=0 Then 'fact1=0, just return
		er=0
		Return fac1
	Else
		'check to see if fac2 is a power of ten
		is_power_of_two=0
		If fac2.mantissa[0]=&H10000000ul Then
			is_power_of_two=1
			For i=1 To dwords
				If fac2.mantissa[i]<>0 Then
					is_power_of_two=0
					Exit For
				End If
			Next
		End If
		'if fac2 is a power of ten then all we need to do is to adjust the sign and exponent and we are finished
		If is_power_of_two=1 Then
			fac1.sign=fac1.sign Xor fac2.sign
			fac1.exponent=fac1.exponent-fac2.exponent+BIAS+1
			Return fac1
		End If

		#Define min(a,b) Iif(((a)<(b)),(a),(b))

		#Macro realw(w, j)
			((w(j - 1)*b + w(j))*b + w(j + 1))*b +Iif(Ubound(w)>=j+2,w(j+2),0)
		#Endmacro

		#Macro subtract(w, q, d, ka, kb)
			For j=ka To kb
				w(j) = w(j) - q*d(j - ka + 2)
			Next
		#Endmacro

		#Macro normalize(w, ka, q)
			w(ka) = w(ka) + w(ka - 1)*b
			w(ka - 1) = q
		#Endmacro

		#Macro finalnorm(w, kb)
			For j=kb To 3 Step -1
				carry=Iif(w(j)<0, ((-w(j) - 1)\b) + 1, Iif(w(j) >= b, -(w(j)\b), 0))
				w(j) = w(j) + carry*b
				w(j - 1) = w(j - 1) - carry
			Next
		#Endmacro

		'Dim As Double result(1 To 2*dwords+3), n(1 To 2*dwords+3), d(1 To 2*dwords+3)
		Dim As Double result(2*dwords+4), n(2*dwords+4), d(2*dwords+4)
		Const b=&H10000   
		Dim As Integer j, last, laststep, q, t
		Dim As Integer stp, carry
		Dim As Double xd, xn, rund
		Dim As Double w(1 To Ubound(n)+4)

		For j=0 To dwords*2 step 2
			n(j+3)=fac1.wmantissa[j] '\&H10000
			n(j+2)=fac1.wmantissa[j+1] 'Mod &H10000
			d(j+3)=fac2.wmantissa[j] '\&H10000
			d(j+2)=fac2.wmantissa[j+1] 'Mod &H10000
		Next
		n(1)=(fac1.exponent And &h7FFFFFFF)-BIAS-1
		d(1)=(fac2.exponent And &h7FFFFFFF)-BIAS-1
		'For j=Ubound(n) To Ubound(w)
		'	w(j)=0
		'Next
		t=Ubound(n)-1
		w(1)=n(1)-d(1)+1
		w(2)=0
		For j=2 To Ubound(n)
			w(j+1)=n(j)
		Next   
		xd = (d(2)*b + d(3))*b + d(4) + d(5)/b
		laststep = t + 2
		For stp=1 To laststep
			xn=RealW(w, (stp + 2))
			q=Int(xn/xd)
			last = Min(stp + t + 1, Ubound(W))
			subtract(w, q, d, (stp + 2), last)
			normalize(w, (stp + 2), q)
		Next
		FinalNorm(w, (laststep + 1))
		laststep = Iif(w(2) = 0, laststep, laststep - 1)
		rund = w(laststep + 1)/b
		w(laststep) = w(laststep) + Iif(rund >= 0.5, 1, 0)
		If w(2)=0 Then
			For j=1 To t+1
				result(j)=w(j+1)
			Next
		Else
			For j=1 To t+1
				result(j)=w(j)
			Next
		End If
		result(1) = Iif(w(2) = 0, w(1) - 1, w(1))

		For j=0 To dwords*2 step 2
			'fac1.mantissa[j]=result(2*j+2)*&H10000+result(2*j+3)
			fac1.wmantissa[j]=result(j+3)
			fac1.wmantissa[j+1]=result(j+2)
		Next
		'fac1.wmantissa[dwords*2+1]=result(2*dwords+2)+result(2*dwords+4)/&h10000
		NORM_FAC1(fac1, dwords)
		fac1.exponent=(result(1)+BIAS)
	End If
	fac1.sign=fac1.sign Xor fac2.sign
	Return fac1
End Function

Function fpipow(Byref x As BigFloat_struct, Byval e As Longint, Byval dwords As Long=NUM_DWORDS) As BigFloat_struct
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	'take x to an Long power
	Dim As BigFloat_struct y=x
	Dim As BigFloat_struct z, one
	Dim As Longint n, c=0
	Dim As Integer i

	n = Abs(e)
	one.exponent=(BIAS+1)
	one.mantissa[0]=&h10000000ul
	z=one
	While n>0
		While (n And 1)=0
			n\=2
			y=fpmul(y, y, dwords)
			c+=1
		Wend
		n-=1
		z=fpmul(y, z, dwords)
		c+=1
	Wend

	If e<0 Then
		z=fpdiv(one, z, dwords)
	End If

	Return z
End Function

Function dbl2fp(Byval x As Double) As BigFloat_struct
	Dim As BigFloat_struct bf
	Dim As Ulongint n, e
	Dim As Long sign
	If x<0 Then sign=&h8000
	x=Abs(x)
	n=Peek ( Ulongint, @x )
	e=n
	n=Cast(Ulongint, (n Shl 12))
	n=Cast(Ulongint, (n Shr 4))
	n+=&h1000000000000000ull
	bf.mantissa[0]=Cast(Ulongint, (n Shr 32))
	n=e
	n=Cast(Ulongint, (n Shl 40))
	n=Cast(Ulongint, (n Shr 32))
	bf.mantissa[1]=n
	n=n+&h1000000000000000ull
	e=Cast(Ulongint, (e Shr 52))
	e=e-&h3FFul
	bf.exponent=e+BIAS+1
	bf.sign=sign
	Return bf
End Function

Function fp2dbl(Byref x As BigFloat_struct) As Double
	Dim As Double dbl
	Dim As Ulongint n, e
	Dim As Ushort ex
	Dim As Long sign
	If x.sign<>0 Then
		sign=-1
	Else
		sign=1
	End If
	If x.exponent>0 Then
		ex=(x.exponent And &h7FFFFFFF)-BIAS-1
	Else
		ex=0
	End If
	n=x.mantissa[0]
	n-=&h10000000ul
	n=Cast(Ulongint, (n Shl 24))
	e=&h3FF+ex
	e=e*&h10000000000000ull
	n=n+e
	e=x.mantissa[1]\&h100
	n=n+e
	Poke Ulongint,@dbl,n
	Return dbl*sign
End Function

Function fp2ui(Byref x As BigFloat_struct, Byval dwords As Long=NUM_DWORDS) As Ulong
	If dwords>NUM_DWORDS Then dwords=NUM_DWORDS
	Dim As BigFloat_struct fac1
	Dim As Double n
	fac1.exponent=0
	fac1.mantissa[0]=x.mantissa[0]
	n=fp2dbl(x)
	Return Fix(n)
End Function

Function str2fp_aux(Byval value As String, Byref s As Long, Byref ex As Long ) As String
	Dim As Integer j,d,e,ep,es,i,f,fp,fln
	Dim As String c,f1,f2,f3, ts
	Dim As Ulong ulng

	j=1
	s=1
	d=0
	e=0
	ep=0
	ex=0
	es=1
	i=0
	f=0
	fp=0
	f1=""
	f2=""
	f3=""
	value=Ucase(value)
	fln=Len(value)

	While j<=fln
		c=Mid(value,j,1)
		If ep=1 Then
			If c=" " Then
				j=j+1
				Continue While
			Endif
			If c="-" Then
				es=-es
				c=""
			Endif
			If c="+" Then
				j=j+1
				Continue While
			Endif
			If (c="0") And (f3="") Then
				j=j+1
				Continue While
			Endif
			If (c>"/") And (c<":") Then 'c is digit between 0 and 9
				f3=f3+c
				ex=10*ex+(Asc(c)-48)
				j=j+1
				Continue While
			Endif
		Endif

		If c=" " Then
			j=j+1
			Continue While
		Endif
		If c="-" Then
			s=-s
			j=j+1
			Continue While
		Endif
		If c="+" Then
			j=j+1
			Continue While
		Endif
		If c="." Then
			If d=1 Then
				j=j+1
				Continue While
			Endif
			d=1
		Endif
		If (c>"/") And (c<":") Then 'c is digit between 0 and 9
			If ((c="0") And (i=0)) Then
				If d=0 Then
					j=j+1
					Continue While
				Endif
				If (d=1) And (f=0) Then
					e=e-1
					j=j+1
					Continue While
				Endif
			Endif
			If d=0 Then
				f1=f1+c
				i=i+1
			Else
				If (c>"0") Then
					fp=1
				Endif
				f2=f2+c
				f=f+1
			Endif
		Endif
		If c="E" Or c="D" Then
		ep=1
		Endif
		j=j+1
	Wend
	If fp=0 Then
		f=0
		f2=""
	Endif

	If s=-1 Then s=&h8000 Else s=0

	f1=f1+f2
	f1=Mid(f1,1,1)+Right(f1,Len(f1)-1)
	fln=Len(f1)
	If fp=0 Andalso ex=0 Then
		ex=es*(fln-1)
	Else
		ex=es*((ex-1)+i+e)
	End If

	If fln>((NUM_BITS+16)*0.3010299956639811) Then
		f1=Mid(f1,1,((NUM_BITS+16)*0.3010299956639812)-1)
	Endif

	Return f1
End Function

Function str2fp(Byref x As String) As BigFloat_struct
	Dim As Long strlen, i, n, ex, sign, ten
	Dim As String s2, strin=x
	Dim As BigFloat_struct y, z, pw

	strin=str2fp_aux(strin, sign, ex)
	strin=rtrim(strin,"0")
	strlen=Len(strin)

	n=8
	ten=Valuint("1"+String(n,"0"))
	If strlen>n Then
		s2=Left(strin, n)
		strin=Mid(strin, n+1)
	Else
		z=ui2fp(Valuint(strin))
		pw=ui2fp(10)
		pw=fpipow(pw, strlen-ex-1)
		z=fpdiv(z, pw)
		Return z
	End If
	z=ui2fp(Valuint(s2))

	While Len(strin)>=n
		s2=Left(strin, n)
		strin=Mid(strin, n+1)
		y=ui2fp(Valuint(s2))
		z=fpmul_ui(z, ten)
		z=fpadd(z,y)
	Wend
	i=len(strin)
	if i>0 then
		ten=Valuint("1"+String(i,"0"))
		y=ui2fp(Valuint(strin))
		z=fpmul_ui(z, ten)
		z=fpadd(z,y)
	end if
	pw=ui2fp(10)
	pw=fpipow(pw,strlen-ex-1)
	z=fpdiv(z, pw)
	z.sign=sign
	Return z
End Function

Function fp2str(Byref zz As BigFloat_struct, Byval digits As Long=NUMBER_OF_DIGITS+8) As String
	If digits>(NUMBER_OF_DIGITS+8) Or digits<0 Then digits=NUMBER_OF_DIGITS+8
	Dim As Long ex, i, m, n, powten, sign, tn
	Dim As BigFloat_struct y, ten, tenp, z, ep, one, nine, zero
	Dim As String s, s2
	If zz.exponent=0 Then
		Return " 0"
	End If
	digits+=2
	n=8
	one=ui2fp(1)
	nine=ui2fp(9)
	ten=ui2fp(10)
	tenp=ui2fp(Clng("1"+String(n,"0")))
	tn=Clng("1"+String(n,"0"))
	z=zz
	sign=zz.sign
	z.sign=0
	If z.exponent<>0 Then
		ex=(z.exponent And &h7FFFFFFFul)-BIAS-1
	Else
		ex=0
	End If
	m=NUM_BITS-ex
	ep.exponent=-(m+16)+BIAS+1
	ep.mantissa[0]=&h10000000ul
	z=fpadd(z,ep)
	If fpcmp(z,nine)>0 Then
		While fpcmp(z,nine)>0
			z=fpdiv_si(z, 10)
			powten+=1
		Wend
	Elseif fpcmp(z,one)<0 Then
		While fpcmp(z,one)<0
			z=fpmul(z, ten)
			powten-=1
		Wend
	End If

	m=fp2ui(z)
	z=fpfrac(z)
	z=fpmul(z, tenp)
	s=Trim(Str(m))+"."
	For i=1 To digits
		If fpcmp(z, one)<0 Then
			While fpcmp(z, one)<0
				If (Len(s))>=digits Then Exit While
				z=fpmul(z, tenp)
				s=s+String(n,"0")
			Wend
		Else
			If (Len(s))>=digits Then Exit For
			y=fpfix(z)
			m=fp2ui(y)
			z=fpfrac(z)
			z=fpmul(z, tenp)
			s2=Trim(Str(m))
			s2=String(n-len(s2),"0")+s2
			s=s+s2
		End If	
	Next
	s=Ltrim(s, "0")
	If Len(s)>(digits-1) Then
		s=Left(s, digits-1)
	End If
	i=Instr(Trim(s),".")
	
	If i>2 Then
		s=Left(s,i-1)+Mid(s, i+1)
		s=Left(s,1)+"."+Mid(s, 2)
		powten+=1
	Elseif i=1 Then
		s=Mid(s,2)
		s=Left(s,1)+"."+Mid(s,2)
		powten-=1
	End If
	s2=Trim(Str(Abs(powten)))
	If (5-len(s2))>0 Then s2=String(5-len(s2),"0")+s2
	If powten<0 Then
		s2="-"+s2
	Else
		s2="+"+s2
	End If
	s=s+"e"+s2
	If sign<>0 Then
		s="-"+s
	Else
		s=" "+s
	End If
	Return s
End Function

'integer part of num
Function fpfix( Byref num As BigFloat_struct, byref jj as long =0 ) As BigFloat_struct
	Dim As BigFloat_struct ip
	Dim As Long ex, ex2, i, j, k, c

	ex=(num.exponent And &h7FFFFFFFul)-BIAS

	If ex<1 Then
		Return ip
	End If
	If ex>=(NUM_BITS) Then
		Return num
	End If
	ex2=ex\32

	k=ex2
	j=ex Mod 32
	jj=j

	if j>29 then
		ex2+=1
		k=ex2
		j=0
	end if

	While ex2>0
		ex2-=1
		ip.mantissa[ex2]=num.mantissa[ex2]
	Wend

	ip.mantissa[k]=num.mantissa[k]
if jj>29 then
	i=31-jj
	if jj=31 then i-=1
	ip.mantissa[k]=shr32(ip.mantissa[k], (jj+i), c)
	ip.mantissa[k]=shl32(ip.mantissa[k], (jj+i), c)
else
	ip.mantissa[k]=shr32(ip.mantissa[k], (32-j)-3, c)
	ip.mantissa[k]=shl32(ip.mantissa[k], (32-j)-3, c)
end if
	ip.exponent=ex+BIAS
	ip.sign=num.sign
	NORM_FAC1(ip)
	Return ip
End Function

'fractional part of num
Function fpfrac( Byref num As BigFloat_struct ) As BigFloat_struct
	Dim As BigFloat_struct ip, fp
	ip=fpfix(num)
	fp=fpsub(num, ip)
	Return fp
End Function

'returns 1 if integer part is odd
Function fpfix_is_odd( Byref num As bigfloat_struct ) As Long
	Dim As Long ex, j, k, c
	Dim As Ulong m
	
	ex=(num.exponent And &h7FFFFFFF)-BIAS
	If ex<1 Then
		Return 0
	End If
	If ex>=(NUM_BITS) Then
		Print "error in function fpfix_is_odd"
		Return -1
	End If
	k=ex\32
	j=ex Mod 32
	m=num.mantissa[k]
	m=shr32(m, (32-j)-3, c)
	Return m And 1
End Function

'==== test code ====

Dim As Integer n, i, j, k
dim as double tm

Print
Print "this program computes g(y)=f(h(x)^-1)."
Print "where the f(i) coefficients are optional."
Print "if the f(i) are omitted, then g(y)=h(x)^-1 is computed."
Print
Input "Number of input polynomial "; n

Dim As bigfloat a(n), b(n), c(n), d(n), e, t, n0, n1, m0, m1, tmp
Dim As Integer k0, count=0
Dim As String a_

Print
tm=timer

tmp=1
for i=1 to n step 2
	c(i)=tmp/i
	tmp=-tmp
	print using "C(###) = ";i;
	? fp2str(c(i).BigNum, 50)
next

a(1) = 1

t = 1
For i = 1 To n
	t = t / c(1)
	b(i) = a(i) * t
	d(i) = c(i) * t
Next i
If n < 2 Then Goto skip
For k = 2 To n
	e = -d(k)
	k0 = k - 1
	For i = k To n
		For j = i To n
			b(j) = e * b(j - k0) + b(j)
			d(j) = e * d(j - k0) + d(j)
			count+=1
		Next j
	Next i
Next k
skip:
tm=timer-tm

Print
Print "The reversed Polynomial coefficients are:"
Print
tmp=0
For i = 1 To n
	If b(i) <> 0 Then
		Print Using "b(###) = "; i;
		? fp2str(b(i).BigNum, 50)
	End If
Next i

print using "elapsed time = #####.## seconds";tm
print "loop count = ";count

sleep
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: strange malfunction with udt

Post by fxm »

With your above code 'If b(i) <> 0 Then':
- '0' is of Integer type.
- With fbc 1.10.0, only the 'Bigfloat.cast ( ) As Long' operator is called on 'b(i)', then a numeric comparison is done, but 'cast(Long, b(i))' is not a good representation of 'b(i)' => bad comparison.

With the code 'If b(i) <> 0L Then':
- '0L' is of Long type.
- The 'Constructor Bigfloat ( Byval rhs As Long )' is called on '0L', then the 'Operator <> ( Byref lhs As BigFloat, Byref rhs As BigFloat ) As Long' => good comparison'
(same operator calls for fbc 1.09.0 and 'If b(i) <> 0 Then')

Solution: add a matching '<>' operator ( as commented in your code), or add at least a 'Constructor Bigfloat ( Byval rhs As Integer )'.
srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

Re: strange malfunction with udt

Post by srvaldez »

thank you very much fxm :D
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: strange malfunction with udt

Post by fxm »

@Jeff,

I wonder what fix in fbc 1.10.0 leads to such behavior change with 1.09.0 ?
Given the date of this pseudo "regression" that I found: between 2022/11/29 and 2022/11/30, this would correspond to this change:
fbc: passing byval constructor preference
Weird but still a bit annoying: a program working well with fbc 1.09.0, now works badly with fbc 1.10.0 !

But admittedly that program was not coded in the safest way (no matching '<>' operator and no matching conversion constructor):
- the parameters of the overload operator '<>' do not both match the expression used (the two parameters are of the same type in the overload operator definition), then several possible conversions can compete in lower priority,
- either we convert the term on the left into the type of the term on the right, or we convert the term on the right into the type of the term on the left, before solving the inequality,
- but the choice between these two conversions (without knowing the specific context) is not obvious,
- currently, if there is an exact matching conversion constructor, it takes precedence over a matching cast operator, which is a good choice at first sight.
coderJeff
Site Admin
Posts: 4323
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: strange malfunction with udt

Post by coderJeff »

@srvaldez, thank-you for the code to demonstrate.
fxm wrote: Jan 10, 2023 18:41 I wonder what fix in fbc 1.10.0 leads to such behavior change with 1.09.0 ?
Given the date of this pseudo "regression" that I found: between 2022/11/29 and 2022/11/30, this would correspond to this change:
fbc: passing byval constructor preference
Weird but still a bit annoying: a program working well with fbc 1.09.0, now works badly with fbc 1.10.0 !
I think the change was here: fbc: internal: symbFind*() API . Next chance I get I will check usage. I don't have time right now though. I was trying to get rid of some the logic based on recursion counting in to internal functions. The are a few places where functions make a decision based on how many times that particular function has been recursed in to, but the counter is global and so can get different behaviours depending on the code path to that function. The change is probably ok, just need to understand why it also change the comparison, and where else in compiler needs updates.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: strange malfunction with udt

Post by fxm »

coderJeff wrote: Jan 11, 2023 10:51 I think the change was here: fbc: internal: symbFind*() API .
Indeed, I was wrong by one month when I searched in the commit list (I looked for December instead of November).

In any case, the current pseudo "regression" does not bother me too much because it occurs on code that has a double non-safety for me:
- no matching '<>' operator with the used expression,
- and no conversion constructor exactly matching with the two types used in the expression, but only a cast operator matching.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: strange malfunction with udt

Post by fxm »

With the following code, one can check the different constructors/operators priorities when evaluating the expression 'u <> 0' ('u' being a UDT instance):

Code: Select all

#define UDT_ctor_from_integer               '' A
#define UDT_ctor_from_long                  '' B
#define UDT_cast_to_integer                 '' C
#define UDT_cast_to_long                    '' D
#define op_inequal_from_UDT_from_UDT        '' E
#define op_inequal_from_UDT_from_integer    '' F

'' fbc version   1.09.0   1.10.0
''  Priority 1      F        F
''  Priority 2     A+E      A+E
''  Priority 3     B+E       C
''  Priority 4      C        D
''  Priority 5      D

Type UDT
    Dim As Integer I
    Declare Constructor()
    #ifdef UDT_ctor_from_integer
        Declare Constructor(Byval i As Integer)
    #endif
    #ifdef UDT_ctor_from_long
        Declare Constructor(Byval l As Long)
    #endif
    #ifdef UDT_cast_to_integer
        Declare Operator Cast() As Integer
    #endif
    #ifdef UDT_cast_to_long
        Declare Operator Cast() As Long
    #endif
    Declare Destructor()
End Type

Dim Shared AS UDT u

Constructor UDT()
    If @This <> @u Then
        Print "    Constructor UDT()"
    End If
End Constructor

#ifdef UDT_ctor_from_integer
    Constructor UDT(Byval i As Integer)
        Print "    Constructor UDT(Byval As Integer)"
        This.I = i
    End Constructor
#endif

#ifdef UDT_ctor_from_long
    Constructor UDT(Byval l As Long)
        Print "    Constructor UDT(Byval As Long)"
        This.I = l
    End Constructor
#endif

#ifdef UDT_cast_to_integer
    Operator UDT.Cast() As Integer
        Print "    Operator UDT.Cast() As Integer"
        Return This.I
    End Operator
#endif

#ifdef UDT_cast_to_long
    Operator UDT.Cast() As Long
        Print "    Operator UDT.Cast() As Long"
        Return This.I
    End Operator
#endif

Destructor UDT()
    If @This <> @u Then
        Print "  Destructor UDT()"
    End If
End Destructor

#ifdef op_inequal_from_UDT_from_UDT
    Operator <>(Byref ul As UDT, Byref ur As UDT) As Integer
        Print "    Operator <>(Byref As UDT, Byref As UDT) As Integer"  
        Return ul.I <> ur.I
    End Operator
#endif

#ifdef op_inequal_from_UDT_from_integer
    Operator <>(Byref ul As UDT, Byref ir As Integer) As Integer
        Print "    Operator <>(Byref As UDT, Byref As Integer) As Integer"  
        Return ul.I <> ir
    End Operator
#endif

Print "'u <> 0'"
If u <> 0 Then End If

Sleep

- For fbc 1.09.0:

Code: Select all

Priority 1:
    Operator <>(Byref As UDT, Byref As Integer) As Integer
Priority 2:
    Constructor UDT(Byval As Integer)
    Operator <>(Byref As UDT, Byref As UDT) As Integer
  Destructor UDT()
Priority 3:
    Constructor UDT(Byval As Long)
    Operator <>(Byref As UDT, Byref As UDT) As Integer
  Destructor UDT()
Priority 4:
    Operator UDT.Cast() As Integer
Priority 5:
    Operator UDT.Cast() As Long

- For fbc 1.10.0:

Code: Select all

Priority 1:
    Operator <>(Byref As UDT, Byref As Integer) As Integer
Priority 2:
    Constructor UDT(Byval As Integer)
    Operator <>(Byref As UDT, Byref As UDT) As Integer
  Destructor UDT()
Priority 3:
    Operator UDT.Cast() As Integer
Priority 4:
    Operator UDT.Cast() As Long

The priority 3 existing with fbc 1.09.0 disappeared with fbc 1.10.0 (even in 32-bit), and the UDT_ctor_from_long is never called on an Integer value for the conversion (and no priority 5 with fbc 1.10.0).

But this bad behavior of the UDT_ctor_from_long not being called on an Integer value (with fbc 1.10.0) seems to be restricted to a particular context as here. For example, no problem for a simple copy-construction ('Dim As UDT u = 0').
Post Reply