variadic integer parameter
variadic integer parameter
I have a library of procedures with variadic parameters that are used by some customers which contain a list of string keywords, each followed by a numeric/boolean value. One user continues to enter a real-valued parameter that just happens to also be integer valued without the decimal point. I am tired of him complaining when the call does not work as expected because he forgot to insert a terminal decimal point.
Is there a safe and sure method of determining an integer value stored in the double value I expect to see when processing this argument? In some cases, the integer can be quite a large value. Or is there some way that I can force all numeric values to be passed as double and not an integer?
Thanks
Wally
Is there a safe and sure method of determining an integer value stored in the double value I expect to see when processing this argument? In some cases, the integer can be quite a large value. Or is there some way that I can force all numeric values to be passed as double and not an integer?
Thanks
Wally
Re: variadic integer parameter
You can first call a variadic macro which will call the variadic procedure, but only after checking all numeric arguments (presence of a decimal point).
Therefore, a run-time error('Error 1' : Illegal function call) can then be triggered in case of missing decimal point in a numeric argument.
But this method requires that numeric arguments be passed as numeric literals.
No direct means is provided to recursively access individual arguments in the variable argument list of a macro.
To distinguish between the different arguments passed by the variable argument list, one can first convert the variable argument list to a string literal using the '#' stringize operator, then differentiate in this string literal each passed argument by locating the separators (a comma).
Example for the principle (one could do more complete tests):
One can even include the variadic procedure body in the variadic macro body:
Therefore, a run-time error('Error 1' : Illegal function call) can then be triggered in case of missing decimal point in a numeric argument.
But this method requires that numeric arguments be passed as numeric literals.
No direct means is provided to recursively access individual arguments in the variable argument list of a macro.
To distinguish between the different arguments passed by the variable argument list, one can first convert the variable argument list to a string literal using the '#' stringize operator, then differentiate in this string literal each passed argument by locating the separators (a comma).
Example for the principle (one could do more complete tests):
Code: Select all
#macro printStringDoubleCouples(count, args...)
Scope
Dim As String arg(Any)
Dim As Integer n
Dim As String s = #args
Do
Dim As Integer k = InStr(1, s, ",")
n += 1
If k = 0 Then
If (n Mod 2 = 1) Orelse (Instr(1, s, ".") = 0) Then
Error 1
Else
Exit Do
End If
End If
If (n Mod 2 = 0) Andalso (Instr(1, Left(s, k - 1), ".") = 0) Then
Error 1
End If
s = Mid(s, k + 1)
Loop
End Scope
printStringDoubleCouples0(count, args)
#endmacro
Sub printStringDoubleCouples0 Cdecl(Byval count As Integer, ...)
Dim As String s
Dim As Double d
Dim As Cva_List args
Cva_Start(args, count)
For i As Integer = 1 to count
s = *Cva_Arg(args, ZString Ptr)
d = Cva_Arg(args, Double)
Print s, d
Next i
Cva_End(args)
Print
End Sub
'-----------------------------------------------------------------------------
#macro printLiteralString(s)
Print #s
#endmacro
printLiteralString("printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3., "NB 4", 4.)")
printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3., "NB 4", 4.)
printLiteralString("printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3, "NB 4", 4.)")
printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3, "NB 4", 4.)
Sleep
Code: Select all
"printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3., "NB 4", 4.)" Nb 1 1 Nb 2 2 Nb 3 3 NB 4 4 "printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3, "NB 4", 4.)" Aborting due to runtime error 1 (illegal function call) at line 48 of C:\.....
One can even include the variadic procedure body in the variadic macro body:
Code: Select all
#macro printStringDoubleCouples(count, args...)
#ifndef printStringDoubleCouples0
Sub printStringDoubleCouples0 Cdecl(Byval count_ As Integer, ...)
Dim As String s_
Dim As Double d_
Dim As Cva_List args_
Cva_Start(args_, count_)
For i As Integer = 1 to count_
s_ = *Cva_Arg(args_, ZString Ptr)
d_ = Cva_Arg(args_, Double)
Print s_, d_
Next i
Cva_End(args_)
Print
End Sub
#endif
Scope
Dim As String arg(Any)
Dim As Integer n
Dim As String s = #args
Do
Dim As Integer k = InStr(1, s, ",")
n += 1
If k = 0 Then
If (n Mod 2 = 1) Orelse (Instr(1, s, ".") = 0) Then
Error 1
Else
Exit Do
End If
End If
If (n Mod 2 = 0) Andalso (Instr(1, Left(s, k - 1), ".") = 0) Then
Error 1
End If
s = Mid(s, k + 1)
Loop
End Scope
printStringDoubleCouples0(count, args)
#endmacro
'-----------------------------------------------------------------------------
#macro printLiteralString(s)
Print #s
#endmacro
printLiteralString("printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3., "NB 4", 4.)")
printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3., "NB 4", 4.)
printLiteralString("printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3, "NB 4", 4.)")
printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3, "NB 4", 4.)
Sleep
Re: variadic integer parameter
Stick to a macro example:
Code: Select all
#macro SetValues(udt,limit,StartVal...)
#macro split()
s+=","
For n As Long=0 To Len(s)-1
t+=Chr(s[n])
If s[n]=44 Then
Redim Preserve StringArray(Ubound(StringArray)+1)
StringArray(Ubound(StringArray))=Str(t)
t=""
End If
Next n
#endmacro
Scope
Dim As String t
Redim As String StringArray()
Dim As Long count,c2
Var s=#StartVal
split()
For r1 As Long=1 To limit
#If Len(#udt)<>0
Redim Preserve udt(Ubound(udt)+1)
udt(c2).s=StringArray(count)
udt(c2).db=Val(StringArray(count+1))
' print StringArray(count),StringArray(count+1)
r1+=1
c2+=1
count+=1
#Else
Print StringArray(count);" ";
#endif
count+=1
Next
Print
End Scope
#endmacro
Print "Have a look at ... values:"
SetValues(,10,"num 8",8,"num 47",47,"num 3.3",3.3,"num 500",500,"last one",-1)
Print
Print
Type udt
As String s
As Double db
End Type
Redim As udt u(),v()
SetValues(u,10,"num 8",8,"num 47",47,"num 3.3",3.3,"num 500",500,"last one",-1)
For n As Long=Lbound(u) To Ubound(u)
Print n;tab(10);u(n).s;tab(40);u(n).db
Next
print
Print "Have a look at ... values:"
SetValues(,12,"eight point eight",8.8,"forty seven",47,"3 point 3",3.3,"five hundred",500,"second last one",-1,"press a key",.5)
SetValues(v,12,"eight point eight",8.8,"forty seven",47,"3 point 3",3.3,"five hundred",500,"second last one",-1,"press a key",.5)
print
print
For n As Long=Lbound(v) To Ubound(v)
Print n;tab(10);v(n).s;tab(40);v(n).db
Next
Sleep
Re: variadic integer parameter
Thank you for your advice. I already have a routine that breaks down the list at run time. I was just looking for maybe a function or advice that given a 64-bit pattern in a Double valued variable, I could reliably determine if the bit pattern was an integer or really a double value.
Thanks for everything.
Wally
Thanks for everything.
Wally
Re: variadic integer parameter
If we limit the maximum number of variadic arguments to a value (at maximum 8 pairs of variadic arguments in the case below), then we can systematically force the conversion of numeric arguments (literals or variables) to DOUBLE datatype:
Code: Select all
#macro printStringDoubleCouples(count, args...)
#ifndef printStringDoubleCouples0
Sub printStringDoubleCouples0 Cdecl(Byval count_ As Integer, ...)
Dim As String s_
Dim As Double d_
Dim As Cva_List args_
Cva_Start(args_, count_)
For i As Integer = 1 to count_
s_ = *Cva_Arg(args_, ZString Ptr)
d_ = Cva_Arg(args_, Double)
Print s_, d_
Next i
Cva_End(args_)
Print
End Sub
#endif
#if __FB_ARG_COUNT__(args) = 2
printStringDoubleCouples0(count, _
__FB_ARG_EXTRACT__(0, args), Cast(Double, __FB_ARG_EXTRACT__(1, args)))
#elseif __FB_ARG_COUNT__(args) = 4
printStringDoubleCouples0(count, _
__FB_ARG_EXTRACT__(0, args), Cast(Double, __FB_ARG_EXTRACT__(1, args)), _
__FB_ARG_EXTRACT__(2, args), Cast(Double, __FB_ARG_EXTRACT__(3, args)))
#elseif __FB_ARG_COUNT__(args) = 6
printStringDoubleCouples0(count, _
__FB_ARG_EXTRACT__(0, args), Cast(Double, __FB_ARG_EXTRACT__(1, args)), _
__FB_ARG_EXTRACT__(2, args), Cast(Double, __FB_ARG_EXTRACT__(3, args)), _
__FB_ARG_EXTRACT__(4, args), Cast(Double, __FB_ARG_EXTRACT__(5, args)))
#elseif __FB_ARG_COUNT__(args) = 8
printStringDoubleCouples0(count, _
__FB_ARG_EXTRACT__(0, args), Cast(Double, __FB_ARG_EXTRACT__(1, args)), _
__FB_ARG_EXTRACT__(2, args), Cast(Double, __FB_ARG_EXTRACT__(3, args)), _
__FB_ARG_EXTRACT__(4, args), Cast(Double, __FB_ARG_EXTRACT__(5, args)), _
__FB_ARG_EXTRACT__(6, args), Cast(Double, __FB_ARG_EXTRACT__(7, args)))
#elseif __FB_ARG_COUNT__(args) = 10
printStringDoubleCouples0(count, _
__FB_ARG_EXTRACT__(0, args), Cast(Double, __FB_ARG_EXTRACT__(1, args)), _
__FB_ARG_EXTRACT__(2, args), Cast(Double, __FB_ARG_EXTRACT__(3, args)), _
__FB_ARG_EXTRACT__(4, args), Cast(Double, __FB_ARG_EXTRACT__(5, args)), _
__FB_ARG_EXTRACT__(6, args), Cast(Double, __FB_ARG_EXTRACT__(7, args)), _
__FB_ARG_EXTRACT__(8, args), Cast(Double, __FB_ARG_EXTRACT__(9, args)))
#elseif __FB_ARG_COUNT__(args) = 12
printStringDoubleCouples0(count, _
__FB_ARG_EXTRACT__(0, args), Cast(Double, __FB_ARG_EXTRACT__(1, args)), _
__FB_ARG_EXTRACT__(2, args), Cast(Double, __FB_ARG_EXTRACT__(3, args)), _
__FB_ARG_EXTRACT__(4, args), Cast(Double, __FB_ARG_EXTRACT__(5, args)), _
__FB_ARG_EXTRACT__(6, args), Cast(Double, __FB_ARG_EXTRACT__(7, args)), _
__FB_ARG_EXTRACT__(8, args), Cast(Double, __FB_ARG_EXTRACT__(9, args)), _
__FB_ARG_EXTRACT__(10, args), Cast(Double, __FB_ARG_EXTRACT__(11, args)))
#elseif __FB_ARG_COUNT__(args) = 14
printStringDoubleCouples0(count, _
__FB_ARG_EXTRACT__(0, args), Cast(Double, __FB_ARG_EXTRACT__(1, args)), _
__FB_ARG_EXTRACT__(2, args), Cast(Double, __FB_ARG_EXTRACT__(3, args)), _
__FB_ARG_EXTRACT__(4, args), Cast(Double, __FB_ARG_EXTRACT__(5, args)), _
__FB_ARG_EXTRACT__(6, args), Cast(Double, __FB_ARG_EXTRACT__(7, args)), _
__FB_ARG_EXTRACT__(8, args), Cast(Double, __FB_ARG_EXTRACT__(9, args)), _
__FB_ARG_EXTRACT__(10, args), Cast(Double, __FB_ARG_EXTRACT__(11, args)), _
__FB_ARG_EXTRACT__(12, args), Cast(Double, __FB_ARG_EXTRACT__(13, args)))
#elseif __FB_ARG_COUNT__(args) = 16
printStringDoubleCouples0(count, _
__FB_ARG_EXTRACT__(0, args), Cast(Double, __FB_ARG_EXTRACT__(1, args)), _
__FB_ARG_EXTRACT__(2, args), Cast(Double, __FB_ARG_EXTRACT__(3, args)), _
__FB_ARG_EXTRACT__(4, args), Cast(Double, __FB_ARG_EXTRACT__(5, args)), _
__FB_ARG_EXTRACT__(6, args), Cast(Double, __FB_ARG_EXTRACT__(7, args)), _
__FB_ARG_EXTRACT__(8, args), Cast(Double, __FB_ARG_EXTRACT__(9, args)), _
__FB_ARG_EXTRACT__(10, args), Cast(Double, __FB_ARG_EXTRACT__(11, args)), _
__FB_ARG_EXTRACT__(12, args), Cast(Double, __FB_ARG_EXTRACT__(13, args)), _
__FB_ARG_EXTRACT__(14, args), Cast(Double, __FB_ARG_EXTRACT__(15, args)))
#else
Error 1
#endif
#endmacro
'-----------------------------------------------------------------------------
#macro printLiteralString(s)
Print #s
#endmacro
printLiteralString("printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3., "NB 4", 4.)")
printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3., "NB 4", 4.)
printLiteralString("Dim As Single x1 = 1")
Dim As Single x1 = 1
printLiteralString("Dim As Integer x2 = 2")
Dim As Integer x2 = 2
printLiteralString("printStringDoubleCouples(4, "Nb 1", x1, "Nb 2", x2, "Nb 3", 3, "NB 4", 4!)")
printStringDoubleCouples(4, "Nb 1", x1, "Nb 2", x2, "Nb 3", 3, "NB 4", 4!)
Sleep
Code: Select all
"printStringDoubleCouples(4, "Nb 1", 1., "Nb 2", 2., "Nb 3", 3., "NB 4", 4.)" Nb 1 1 Nb 2 2 Nb 3 3 NB 4 4 "Dim As Single x1 = 1" "Dim As Integer x2 = 2" "printStringDoubleCouples(4, "Nb 1", x1, "Nb 2", x2, "Nb 3", 3, "NB 4", 4!)" Nb 1 1 Nb 2 2 Nb 3 3 NB 4 4
Re: variadic integer parameter
Regarding the numbers only, you only get two choices for a bare literal , integer or double.
Which makes things a little different for 32 and 64 bits.
A rough and ready method, using 1e-6 as a tester to allocate the required slot of memory for each jump.
The test is abs(Cva_Arg(args2, double ))<1e-6, maybe it could be refined a little?
Which makes things a little different for 32 and 64 bits.
A rough and ready method, using 1e-6 as a tester to allocate the required slot of memory for each jump.
Code: Select all
Sub proc cdecl(count As Integer, ... )
Dim args As Cva_List
Dim args2 As any ptr
Cva_Start( args, count )
For i As long = 1 To count
args2=args
'print Cva_Arg(args,double )
print i,iif( abs(Cva_Arg(args2, double ))<1e-6,Cva_Arg(args,integer ),Cva_Arg(args,double ))
Next
Cva_End( args )
End Sub
proc(11,1,2,3,4,6.5,rnd,sqr(2),5,6,7,8)
print
proc(20,3,sin(1),2,cos(3),4,int(6.5),rnd-rnd,sqr(2),5,6,7,8,12,13,14,cdbl(15),-8,-9,-10,20)
sleep
Re: variadic integer parameter
Code: Select all
if Frac(x) = 0 then Print "x is an integer"
Re: variadic integer parameter
Thank you that is just what I was looking for.
Wally
Wally
Re: variadic integer parameter
A further refinement (variadic parameters)
Code: Select all
Function check(b As String,n2 As Double) As boolean
If n2=0 Then Return true
If b[0]=48 Then Return false
For n As Long=0 To Len(b)-1-6
If b[n]<>49 Then Return false
Next n
Return true
End Function
Sub proc Cdecl(count As Integer, ... )
Dim args As Cva_List
Dim args2 As Any Ptr
Cva_Start( args, count )
For i As Long = 1 To count
args2=args
Dim As Integer n=-Abs(*Cast(Integer Ptr,args2))
Dim As Double n2=-Abs(*Cast(Double Ptr,args2))
Dim As String b=Bin(n)
Print i,Iif(check(b,n2),Cva_Arg(args,Integer ),Cva_Arg(args,Double ));Tab(40);Iif(check(b,n2),"integer","double");Tab(50);b
Next
Cva_End( args )
End Sub
proc(11,1,2,3,4,6.5,Rnd,Sqr(2),5,6,7,8)
Print
Print
proc(20,3,Sin(1),2,Cos(3),4,Int(6.5),Rnd-Rnd,Sqr(2),5,6,7,8,12,13,14,Cdbl(15),-8,-9,-10,20)
Print
Print
proc(7,8.8,3,-5.3,0,1.,3#,7)
Sleep
-
- Posts: 606
- Joined: Nov 28, 2012 1:27
- Location: CA, USA moving to WA, USA
- Contact:
Re: variadic integer parameter
FRAC()
Never noticed that before. Always pays to just skim all the posts.
david
Never noticed that before. Always pays to just skim all the posts.
david