Forum Discussion

mhupman_60939's avatar
mhupman_60939
Icon for Nimbostratus rankNimbostratus
Nov 07, 2011

iRule Math - Square Root?

I hope I'm simply doing something wrong, but I cannot figure out how to calculate the square root of a number inside an iRule. I tried the sqrt() and pow() TCL functions, but it doesn't seem like those are supported (got errors after applying the iRule). Does anyone know how I can calculate the square root of a number in an iRule?

 

10 Replies

  • Hi mhupman,

     

     

    I did some digging as well and it looks like that Math Function was not included in the custom version of TCL that the LTM uses.

     

     

     

    Math Functions

     

     

    The following TCL based math functions have been included in iRules

     

     

    abs(arg)

     

    Returns the absolute value of arg. Arg may be either integer or floating-point, and the result is returned in the same form.

     

    double(arg)

     

    If arg is a floating-point value, returns arg, otherwise converts arg to floating-point and returns the converted value.

     

    int(arg)

     

    f arg is an integer value of the same width as the machine word, returns arg, otherwise converts arg to an integer by truncation and returns the converted value.

     

    rand()

     

    Returns a pseudo-random floating-point value in the range (0,1). The generator algorithm is a simple linear congruential generator that is not cryptographically secure. Each result from rand completely determines all future results from subsequent calls to rand, so rand should not be used to generate a sequence of secrets, such as one-time passwords. The seed of the generator is initialized from the internal clock of the machine or may be set with the srand function.

     

    round(arg)

     

    If arg is an integer value, returns arg, otherwise converts arg to integer by rounding and returns the converted value.

     

    srand(arg)

     

    The arg, which must be an integer, is used to reset the seed for the random number generator of rand. Returns the first random number (see rand()) from that seed. Each interpreter has its own seed.

     

    wide(arg)

     

    Converts arg to an integer value at least 64-bits wide (by sign-extension if arg is a 32-bit number) if it is not one already.

     

     

     

    You can read the entire article here: iRules 101 - 02 - If and Expressions

     

  • Michael,

    Thanks for the reply. Its very disappointing that they don't support basic math functions - what could be the motivation for that? Anyway, i was able to implement my own (hacky!) square root calculator based on the Nth Root Algorithm (http://en.wikipedia.org/wiki/N-th_root_algorithm). Code snippet below for anyone who might be interested:

    Calcuate the square root. Based on the http://en.wikipedia.org/wiki/N-th_root_algorithm

    set guess [expr {$targetValue/2}]
    for {set i 0} {$i < 32} {incr i} {
      set guess [expr {$guess + $targetValue/$guess}]
      set guess [expr {$guess/2}]
    }
    set answer $guess

    Obviously this doesn't have any special-case handling (1, negative values, etc) and isn't very performant but it works well enough for my use case.

  • Its very disappointing that they don't support basic math functions - what could be the motivation for that?

     

     

    I think the motivation is to keep unnecessary overhead as small as possible. There are very, very rare situations where you would need a sqrt function to make a load balancing decision ;-)

     

     

    I would be interested in your use case!

     

     

    Regards

     

    Kurt Knochner
  • For load balancing decisions, sure - I can't imagine many cases where advanced math functions would be necessary. But there are nearly infinite use cases for iRules. In my particular case, I am building a stats logger based on the Link Tracking CodeShare iRule (http://devcentral.f5.com/wiki/iRules.LinkTracking.ashx). One of the query string parameters my app uses contains a encoded version of the requestor's UserID. I wanted to display the unencoded UserID on that stats page (and also include a hyperlink to our internal CMS for that UserID) and the last step of decoding the UserID is to take the square root of the encoded value :)

     

     

    Regardless of my particular use case, I can't imagine there is significant overhead involved in including the rest of the math functions. TCL compatibility is touted as a feature of the iRule engine - it would be nice if it followed the spec as closely as possible.

     

  • But there are nearly infinite use cases for iRules. In my particular case, I am building a stats logger based on the Link Tracking CodeShare iRule (http://devcentral.f5.com/wiki/iRules.LinkTracking.ashx).

     

     

     

    O.K. I see. My point of view is: Even if it's possible to do a lot of things with an iRule (and I have done strange things to fix broken applications), there are very often better ways to do things offsite, by logging information to an internal system and implement all the required logic there, especially if it's about statistics and other performance data. You'll have more options to implement things (other programming languages) and it does not put an extra load on the balancer.

     

    I wanted to display the unencoded UserID on that stats page (and also include a hyperlink to our internal CMS for that UserID) and the last step of decoding the UserID is to take the square root of the encoded value :)

     

     

    O.K. I see. Is there any special reason for encoding the userid in that way? Sounds a bit like security by obscurity ;-)) Please don't get me wrong !!

     

     

    Regardless of my particular use case, I can't imagine there is significant overhead involved in including the rest of the math functions. TCL compatibility is touted as a feature of the iRule engine - it would be nice if it followed the spec as closely as possible.

     

    As much as I understand your demand, I also understand F5 if they just implement what's really needed. After all this is a load balancer with an included TCL interpreter and not a fully implemented TCL interpreter with some load balancing functionality ;-))

     

     

    BTW: There is another solution to your sqrt problem in V11. You can use "sideband" connections to retrieve data from an external system with TCP or UDP (http://devcentral.f5.com/wiki/iRules.sideband.ashx). So the idea would be: ask an internal system (e.g. a web service) to decode the userid with such a sideband connection. This way, you can implement whatever you need on that web service and have that functionality within an iRule.

     

     

    Regards

     

    Kurt Knochner
  • O.K. I see. My point of view is: Even if it's possible to do a lot of things with an iRule (and I have done strange things to fix broken applications), there are very often better ways to do things offsite, by logging information to an internal system and implement all the required logic there, especially if it's about statistics and other performance data.

    I agree, but it in this case I had a few hours to implement a status page for the Ops team to see who was making requests. It was much faster to use pure iRules then to attempt to integrate multiple systems.

     

     

     

    O.K. I see. Is there any special reason for encoding the userid in that way? Sounds a bit like security by obscurity ;-))

     

     

     

    The UserID in this case is just a unique identifier we use for tracing events. We take the original DB identity value and bitshift it and square it before handing it out to clients to use in their web calls. This is to prevent a typo or transcription error from mixing up two client's data (e.g. UserID's 143 and 144 might be represented as EncUserID 8347362 and 9234873 in the web call). It's not designed to be safe, but to prevent silly errors.

     

     

     

    As much as I understand your demand, I also understand F5 if they just implement what's really needed. After all this is a load balancer with an included TCL interpreter and not a fully implemented TCL interpreter with some load balancing functionality ;-))

     

     

     

    I guess we'll agree to disagree :).

     

     

     

    You can use "sideband" connections to retrieve data from an external system with TCP or UDP (http://devcentral.f5.com/wiki/iRules.sideband.ashx).

     

     

     

    As I mentioned above, I only had a short time period to implement this, so creating a decoding endpoint would have been impractical. However, I didn't know about the sideband connections, I'll read up on them. Thanks!

     

  • Seems like it would be easy enough for F5 to add support for more of the math functions than just rand. You could open a case with F5 Support to request this. However, considering this was just discovered now, I'm guessing the demand for these functions is a bit low :)

     

     

    Aaron
  • George_Watkins_'s avatar
    George_Watkins_
    Historic F5 Account
    I ran into the same issue trying to answer this post: http://devcentral.f5.com/Community/GroupDetails/tabid/1082223/asg/50/aft/2156829/showtab/groupforums/Default.aspx

     

     

    I need round() and pow() to do it cleanly. Demand is growing... :-)

     

     

    -George
  • George_Watkins_'s avatar
    George_Watkins_
    Historic F5 Account
    I found this Tech Tip from Joe (http://devcentral.f5.com/Tutorials/TechTips/tabid/63/articleType/ArticleView/articleId/124/iRules-101--02--If-and-Expressions.aspx) with a list of available math functions in iRules.

     

     

    -George
  • George_Watkins_'s avatar
    George_Watkins_
    Historic F5 Account

    Here is a solution using Newton's method to calculate a square root:

    when HTTP_REQUEST {
      set input [URI::query [HTTP::uri] "input"]
        if { ([HTTP::path] equals "/sqrt") && ($input ne "") } {
          if { $input == 0 } {
            set sqrt 0
          } else {
              set x [expr {abs($input)}]
              while { 1 } {
                set y [expr (($x+($input/$x))/2)]
                if { [expr (abs($x-$y))] < 0.01 } break
                set x $y
              }
              set sqrt $y
          }
        HTTP::respond 200 content "The square root of $input is $sqrt"
      }
    }

    http://test-http-virtual/sqrt?input=144 => "The square root of 144 is 12"

    http://test-http-virtual/sqrt?input=225.25 => "The square root of 225.25 is 15.0083321641"

    http://test-http-virtual/sqrt?input=67108864.0 => "The square root of 67108864.09 is 8192.00000549"

    Hope that helps,

    George