Real to integer conversion?


#1

Can you or are there any plans for introducing real to integer conversion?

In my use case I’ve an array of pre-computed matrices: matrix[20, 20] A_inv[10]. I would like to be able to choose a matrix like A_inv[idx], where idx is calculated from real variables, eq idx = to_integer(ceil(x/5.0)).

The reference manual 2.17 chapter 41.7 states: “The rounding functions cannot be used as indices to arrays because they return real values. Stan may introduce integer-valued versions of these in the future, but as of now, there is no good workaround.”


#2

No. It messes up NUTS.


#3

Only if used for sampling. The other day I wanted to round something to use in the generated quantities block and couldn’t find a way to do it. Is there a trick for that situation?


#4

No, but I don’t think it matters whether it is int or real with no decimal places. In R at least, it is going to be stored with double precision anyway.


#5

I want to use it for indices, shouldn’t affect the sampling (currently I’m using if-else statements to figure out indices from real variables, and that doesn’t mess up the sampling either).


#6

Well, there still is no conversion from real to int and indices have to be int.


#7

If you’re dead-set on it, the best way would probably be to write a binary search function to find the corresponding integer. I’m guessing there’s a good chance that this would not play well with NUTS.

  int bin_search(real x, int min_val, int max_val){
    // This assumes that min_val >= 0 is the minimum integer in range, 
    //  max_val > min_val,
    // and that x has already been rounded. 
    //  It should find the integer equivalent to x.
    int range = (max_val - min_val+1)/2; // We add 1 to make sure that truncation doesn't exclude a number
    int mid_pt = min_val + range;
    int out;
    while(range > 0) {
      if(x == mid_pt){
        out = mid_pt;
        range = 0;
      } else {
        // figure out if range == 1
        range =  (range+1)/2; 
        mid_pt = x > mid_pt ? mid_pt + range: mid_pt - range; 
        }
    }
    return out;
  }

#8

Thanks, that worked.