\lstset{breaklines=true, style=customcpp,basicstyle=\scriptsize\ttfamily}
\begin{lstlisting}[fontadjust]
//Modified CUDA utility for parallel array reduction
__device__ inline void reduce_kernel(float* g_idata, float* g_odata, 
                                     float* sdata, 
                                     unsigned int blockSize);

//Semi-parallel implementation of the Taubin ring fit algorithm
__device__ void Taubin(UTILITY* utility,   //Global memory: utilities
                       float* s_reduction, //Shared memory: array sums
                       Result* Result)     //Global memory: results
{
  float xav,yav;
  int length=Result->nHitsPerCandidate[blockIdx.x];

  //Distribute jobs to blocks and threads
  unsigned int eventIdx = blockIdx.x/4;
  unsigned int tripletIdx = blockIdx.x%4;
  unsigned int beginIdx = 4*MAXHITS*eventIdx + MAXHITS*tripletIdx;
  unsigned int hitIdx = 4*MAXHITS*eventIdx + MAXHITS*tripletIdx + threadIdx.x;

  //Execute function only on busy blocks
  if(eventIdx < Result->actualsize)
    {
      //Erase hit arrays
      utility->xHit[hitIdx] = 0;
      utility->yHit[hitIdx] = 0;

      //If current hit belongs to triplet
      //copy its coordinates and revert shift
      if (utility->x_hits_on_ring[hitIdx] != 0 && utility->y_hits_on_ring[hitIdx] != 0)
      {
    	  utility->xHit[hitIdx] = utility->x_hits_on_ring[hitIdx]
	    - XSHIFT;
    	  utility->yHit[hitIdx] = SQRT3*utility->y_hits_on_ring[hitIdx];
      }
      __syncthreads();
      
      //Compute center of gravity
      reduce_kernel(&utility->xHit[beginIdx], &utility->xm[blockIdx.x],
		    s_reduction, MAXHITS);
      reduce_kernel(&utility->yHit[beginIdx], &utility->ym[blockIdx.x], 
		    s_reduction, MAXHITS);
      xav = utility->xm[blockIdx.x]/length;
      yav = utility->ym[blockIdx.x]/length;
      
      //Erase utility arrays
      utility->uzav[4*eventIdx + tripletIdx] = 0.f;
      utility->z2av[4*eventIdx + tripletIdx] = 0.f;
      utility->u2av[4*eventIdx + tripletIdx] = 0.f;
      utility->v2av[4*eventIdx + tripletIdx] = 0.f;
      utility->uvav[4*eventIdx + tripletIdx] = 0.f;
      utility->uzav[4*eventIdx + tripletIdx] = 0.f;
      utility->vzav[4*eventIdx + tripletIdx] = 0.f;
      
      //If current hit belongs to triplet
      //fill utility arrays
      if(utility->xHit[hitIdx]!=0 
	 && utility->yHit[hitIdx]!=0)
	{
	  utility->u[hitIdx] = utility->xHit[hitIdx] - xav;
	  utility->v[hitIdx] = utility->yHit[hitIdx] - yav;
	  utility->u2[hitIdx] = utility->u[hitIdx] * utility->u[hitIdx];
	  utility->v2[hitIdx] = utility->v[hitIdx] * utility->v[hitIdx];
	  utility->uv[hitIdx] = utility->u[hitIdx] * utility->v[hitIdx];
	  utility->z[hitIdx] = utility->u2[hitIdx] + utility->v2[hitIdx];
	  utility->z2[hitIdx] = utility->z[hitIdx] * utility->z[hitIdx];
	  utility->uz[hitIdx] = utility->u[hitIdx] * utility->z[hitIdx];
	  utility->vz[hitIdx] = utility->v[hitIdx] * utility->z[hitIdx];
	}
      
      //Compute sum of arrays
      reduce_kernel(&utility->u2[beginIdx], &utility->u2av[blockIdx.x],
		    s_reduction, MAXHITS);
      reduce_kernel(&utility->v2[beginIdx], &utility->v2av[blockIdx.x],
		    s_reduction, MAXHITS);
      reduce_kernel(&utility->uv[beginIdx], &utility->uvav[blockIdx.x],
		    s_reduction, MAXHITS);
      reduce_kernel(&utility->z[beginIdx], &utility->zav[blockIdx.x], 
		    s_reduction, MAXHITS);
      reduce_kernel(&utility->z2[beginIdx], &utility->z2av[blockIdx.x],
		    s_reduction, MAXHITS);
      reduce_kernel(&utility->uz[beginIdx], &utility->uzav[blockIdx.x],
		    s_reduction, MAXHITS);
      reduce_kernel(&utility->vz[beginIdx], &utility->vzav[blockIdx.x],
		    s_reduction, MAXHITS);
      
      //The following code is executed once per block
      if(threadIdx.x == 0)
	{
	  //Compute average
	  float zav = utility->zav[blockIdx.x]/length;
	  float z2av = utility->z2av[blockIdx.x]/length;
	  float u2av = utility->u2av[blockIdx.x]/length;
	  float v2av = utility->v2av[blockIdx.x]/length;
	  float uvav = utility->uvav[blockIdx.x]/length;
	  float uzav = utility->uzav[blockIdx.x]/length;
	  float vzav = utility->vzav[blockIdx.x]/length;
	  
	  //Characteristic polynomial coefficients
	  float CovXY = u2av*v2av - uvav* uvav;
	  float VarZ = z2av-zav * zav;
	  float c0 = uzav*(uzav*v2av - vzav*uvav) 
	    + vzav*(vzav*u2av - uzav*uvav) - VarZ*CovXY;
	  float c1 = VarZ*zav  + 4*CovXY*zav - uzav*uzav - vzav*vzav;
	  float c2 = -3*zav*zav - z2av;
	  float c3 = 4*zav;
	  float c22 = c2*2;
	  float c33 = c3*3;
	  
	  //Find the roots of the characteristic polynomial
	  //P(eta) = c0 + c1*eta + c2*eta^2 + c3*eta^3 = 0
	  float eta, eta_new, poly, poly_new, derivative;
	  eta = 0.f;
	  poly = c0;
	  //Newton's method
	  for(int i=0; i<MAX_ITERATIONS; i++)
	    {
	      derivative = c1 + eta*(c22 + eta*c33);
	      eta_new = eta - poly/derivative;
	      if( eta_new==eta || isnan(eta_new) )
	         break;
	      poly_new = c0 + eta_new*(c1 + eta_new*(c2 + eta_new*c3));
	      if( abs(poly_new) >= abs(poly) )
	         break;
	      eta = eta_new;
	      poly = poly_new;
	    }
	  
	  //Compute ring parameters
	  float det = eta*eta - eta*zav + CovXY;
	  float uc = (uzav*(v2av - eta) - vzav*uvav)/(2*det);
	  float vc = (vzav*(u2av - eta) - uzav*uvav)/(2*det);
	  float alpha = uc*uc + vc*vc + zav;
	  
	  //Converted output result
	  Result->radius[blockIdx.x] = sqrtf(alpha)*((XMAX - XMIN)/NX);
	  Result->xCenter[blockIdx.x] = XMIN
	    + (uc + xav)*((XMAX - XMIN)/NX);
	  Result->yCenter[blockIdx.x] = YMIN
	    + ((vc + yav)/SQRT3)*((YMAX - YMIN)/NY);
	}
    }
}
\end{lstlisting}