Forum Discussion
Walter_Kacynski
Aug 11, 2014Cirrostratus
Nested Procs in an iRule
Since iRules don't support the expr ceil(args) function, I'm trying to implement a TCL version that I found at https://searchcode.com/codesearch/view/16742115/
This implement uses multiple reusable procs. When I format my iRule with these procs, the recusion doesn't seem to process correctly and I'm wondering if there are any restrictions here?
The below code results in this error on my system (11.4.1 HF3)
01070151:3: Rule [/Common/math] error: /Common/math:37: error: [undefined procedure: isFloat][isFloat $x]
/Common/math:37: error: [undefined procedure: isInt][isInt $x]
/Common/math:59: error: [undefined procedure: checkFloat][checkFloat $x]
/Common/math:71: error: [undefined procedure: checkNumber][checkNumber $a]
/Common/math:72: error: [undefined procedure: iszero][iszero $a]
/Common/math:109: error: [undefined procedure: bits][bits $delta]
/Common/math:131: error: [undefined procedure: normalize][normalize $number]
/Common/math:145: error: [undefined procedure: opp][opp $try]
These have been copied from
https://searchcode.com/codesearch/view/16742115/
returns 1 if x is a BigFloat, 0 elsewhere
proc isFloat {x} {
a BigFloat is a list of : "F" mantissa exponent delta
if {[llength $x]!=4} {
return 0
}
the marker is the letter "F"
if {[string equal [lindex $x 0] F]} {
return 1
}
return 0
}
checks that n is a BigInt (a number create by math::bignum::fromstr)
proc isInt {n} {
if {[llength $n]>1} {
return 0
}
if {[string is digit $n]} {
return 1
}
return 1
}
checks if each number is either a BigFloat or a BigInt
arguments : each argument is the name of a variable to be checked
proc checkNumber {x} {
if {![isFloat $x] && ![isInt $x]} {
error "input is not an integer, nor a BigFloat"
}
}
checks each variable to be a BigFloat
arguments : each argument is the name of a variable to be checked
proc checkFloat {number} {
if {![isFloat $number]} {
error "BigFloat expected"
}
}
returns 1 if x is null, 0 otherwise
proc iszero {x} {
if {[isInt $x]} {
return [expr {$x==0}]
}
checkFloat $x
now we do some interval rounding : if a number's interval englobs 0,
it is considered to be equal to zero
foreach {dummy integer exp delta} $x {break}
if {$delta>=abs($integer)} {return 1}
return 0
}
returns -A (the opposite)
proc opp {a} {
checkNumber $a
if {[iszero $a]} {
return $a
}
if {[isInt $a]} {
return [expr {-$a}]
}
recursive call
lset a 1 [expr {-[lindex $a 1]}]
return $a
}
bits : computes the number of bits of an integer, approx.
proc bits {int} {
set l [string length [set int [expr {abs($int)}]]]
int<10**l -> log_2(int)=l*log_2(10)
set l [expr {int($l*log(10)/log(2))+1}]
if {$int>>$l!=0} {
error "bad result: $l bits"
}
while {($int>>($l-1))==0} {
incr l -1
}
return $l
}
normalizes a number : Delta (accuracy of the BigFloat)
has to be limited, because the memory use increase
quickly when we do some computations, as the Mantissa and Delta
increase together
The solution : limit the size of Delta to 16 bits
proc normalize {number} {
checkFloat $number
foreach {dummy integer exp delta} $number {break}
set l [bits $delta]
if {$l>16} {
incr l -16
$l holds the supplementary size (in bits)
now we can shift right by $l bits
always round upper the Delta
set delta [expr {$delta>>$l}]
incr delta
set integer [expr {$integer>>$l}]
incr exp $l
}
return [list F $integer $exp $delta]
}
returns the integer part of a BigFloat, as a BigInt
the result is the same one you would have
if you had called [expr {ceil($x)}]
Case C1631422
proc ceil {number} {
checkFloat $number
set number [normalize $number]
if {[iszero $number]} {
return 0
}
foreach {dummy integer exp delta} $number {break}
if {$exp>=0} {
error "not enough precision to perform rounding (ceil)"
}
saving the sign ...
set sign [expr {$integer<0}]
set integer [expr {abs($integer)}]
integer part
set try [expr {$integer>>(-$exp)}]
if {$sign} {
return [opp $try]
}
fractional part
if {($try<<(-$exp))!=$integer} {
return [incr try]
}
return $try
}
These have been copied from
https://searchcode.com/codesearch/view/16742115/
returns 1 if x is a BigFloat, 0 elsewhere
proc isFloat {x} {
a BigFloat is a list of : "F" mantissa exponent delta
if {[llength $x]!=4} {
return 0
}
the marker is the letter "F"
if {[string equal [lindex $x 0] F]} {
return 1
}
return 0
}
checks that n is a BigInt (a number create by math::bignum::fromstr)
proc isInt {n} {
if {[llength $n]>1} {
return 0
}
if {[string is digit $n]} {
return 1
}
return 1
}
checks if each number is either a BigFloat or a BigInt
arguments : each argument is the name of a variable to be checked
proc checkNumber {x} {
if {![isFloat $x] && ![isInt $x]} {
error "input is not an integer, nor a BigFloat"
}
}
checks each variable to be a BigFloat
arguments : each argument is the name of a variable to be checked
proc checkFloat {number} {
if {![isFloat $number]} {
error "BigFloat expected"
}
}
returns 1 if x is null, 0 otherwise
proc iszero {x} {
if {[isInt $x]} {
return [expr {$x==0}]
}
checkFloat $x
now we do some interval rounding : if a number's interval englobs 0,
it is considered to be equal to zero
foreach {dummy integer exp delta} $x {break}
if {$delta>=abs($integer)} {return 1}
return 0
}
returns -A (the opposite)
proc opp {a} {
checkNumber $a
if {[iszero $a]} {
return $a
}
if {[isInt $a]} {
return [expr {-$a}]
}
recursive call
lset a 1 [expr {-[lindex $a 1]}]
return $a
}
bits : computes the number of bits of an integer, approx.
proc bits {int} {
set l [string length [set int [expr {abs($int)}]]]
int<10**l -> log_2(int)=l*log_2(10)
set l [expr {int($l*log(10)/log(2))+1}]
if {$int>>$l!=0} {
error "bad result: $l bits"
}
while {($int>>($l-1))==0} {
incr l -1
}
return $l
}
normalizes a number : Delta (accuracy of the BigFloat)
has to be limited, because the memory use increase
quickly when we do some computations, as the Mantissa and Delta
increase together
The solution : limit the size of Delta to 16 bits
proc normalize {number} {
checkFloat $number
foreach {dummy integer exp delta} $number {break}
set l [bits $delta]
if {$l>16} {
incr l -16
$l holds the supplementary size (in bits)
now we can shift right by $l bits
always round upper the Delta
set delta [expr {$delta>>$l}]
incr delta
set integer [expr {$integer>>$l}]
incr exp $l
}
return [list F $integer $exp $delta]
}
returns the integer part of a BigFloat, as a BigInt
the result is the same one you would have
if you had called [expr {ceil($x)}]
Case C1631422
proc ceil {number} {
checkFloat $number
set number [normalize $number]
if {[iszero $number]} {
return 0
}
foreach {dummy integer exp delta} $number {break}
if {$exp>=0} {
error "not enough precision to perform rounding (ceil)"
}
saving the sign ...
set sign [expr {$integer<0}]
set integer [expr {abs($integer)}]
integer part
set try [expr {$integer>>(-$exp)}]
if {$sign} {
return [opp $try]
}
fractional part
if {($try<<(-$exp))!=$integer} {
return [incr try]
}
return $try
}
- nitassEmployee
did you forget call command?
call
https://devcentral.f5.com/wiki/irules.call.ashxe.g.
config [root@ve11a:Active:In Sync] config tmsh list ltm rule qux ltm rule qux { proc test1 { x } { log local0. "test1: $x" } proc test2 { y } { log local0. "test2: $y" call test1 $y } when RULE_INIT { if { [TMM::cmp_group] == 0 and [TMM::cmp_unit] == 0 } { call test1 1 call test2 2 } } } /var/log/ltm [root@ve11a:Active:In Sync] config tail -f /var/log/ltm Aug 16 22:54:09 ve11a info tmm[29362]: Rule /Common/qux : test1: 1 Aug 16 22:54:09 ve11a info tmm[29362]: Rule /Common/qux : test2: 2 Aug 16 22:54:09 ve11a info tmm[29362]: Rule /Common/qux : test1: 2
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects