@@ -396,47 +396,49 @@ template <typename State>
396396bool propagateHelixWithJacobian (State& state, float targetZ, float bz, DenseMatrix5& jacobian) noexcept
397397{
398398 identity (jacobian);
399- const double dz = static_cast < double >( targetZ) - state.referenceCoordinate ;
400- if (dz == 0 .) {
399+ const float dz = targetZ - state.referenceCoordinate ;
400+ if (dz == 0 .f ) {
401401 return true ;
402402 }
403- const double tanl = state.parameters [3 ];
404- const double inverseQPt = state.parameters [4 ];
405- if (tanl == 0 . || bz == 0 .f || inverseQPt == 0 .) {
403+ const float tanl = state.parameters [3 ];
404+ const float inverseQPt = state.parameters [4 ];
405+ if (tanl == 0 .f || bz == 0 .f || inverseQPt == 0 .f ) {
406406 return false ;
407407 }
408- const double n = dz / tanl;
409- const double curvatureScale = -std::abs (static_cast < double >( o2::constants::math::B2C ) ) * bz;
410- const double halfAnglePerQPt = 0.5 * curvatureScale * n;
411- const double halfAngle = inverseQPt * halfAnglePerQPt;
412- double sinc, sincDerivative;
413- if (std::abs (halfAngle) < 0.01 ) {
408+ const float n = dz / tanl;
409+ const float curvatureScale = -std::abs (o2::constants::math::B2C ) * bz;
410+ const float halfAnglePerQPt = 0 .5f * curvatureScale * n;
411+ const float halfAngle = inverseQPt * halfAnglePerQPt;
412+ float sinc, sincDerivative;
413+ if (std::abs (halfAngle) < 0 .25f ) {
414414 // sin(h)/h and its derivative, including their limits at h = 0.
415- const double h2 = halfAngle * halfAngle;
416- sinc = 1 . + h2 * (-1 . / 6 . + h2 * (1 . / 120 . - h2 / 5040 .));
417- sincDerivative = halfAngle * (-1 . / 3 . + h2 * (1 . / 30 . - h2 / 840 .));
415+ // Keep the cancellation-prone derivative quotient away from small h.
416+ // At |h| <= 0.25 the omitted terms are below float precision.
417+ const float h2 = halfAngle * halfAngle;
418+ sinc = std::fma (h2, std::fma (h2, std::fma (h2, -1 .f / 5040 .f , 1 .f / 120 .f ), -1 .f / 6 .f ), 1 .f );
419+ sincDerivative = halfAngle * std::fma (h2, std::fma (h2, -1 .f / 840 .f , 1 .f / 30 .f ), -1 .f / 3 .f );
418420 } else {
419421 sinc = std::sin (halfAngle) / halfAngle;
420422 sincDerivative = (std::cos (halfAngle) - sinc) / halfAngle;
421423 }
422- const double phi = state.parameters [2 ];
423- const double sinMid = std::sin (phi + halfAngle);
424- const double cosMid = std::cos (phi + halfAngle);
425- const double endPhi = phi + 2 . * halfAngle;
426- const double dx = n * sinc * cosMid;
427- const double dy = n * sinc * sinMid;
424+ const float phi = state.parameters [2 ];
425+ const float sinMid = std::sin (phi + halfAngle);
426+ const float cosMid = std::cos (phi + halfAngle);
427+ const float endPhi = phi + 2 .f * halfAngle;
428+ const float dx = n * sinc * cosMid;
429+ const float dy = n * sinc * sinMid;
428430
429431 jacobian[0 ][2 ] = -dy;
430432 jacobian[1 ][2 ] = dx;
431433 jacobian[0 ][3 ] = -n / tanl * std::cos (endPhi);
432434 jacobian[1 ][3 ] = -n / tanl * std::sin (endPhi);
433- jacobian[0 ][4 ] = n * halfAnglePerQPt * (sincDerivative * cosMid - sinc * sinMid);
434- jacobian[1 ][4 ] = n * halfAnglePerQPt * (sincDerivative * sinMid + sinc * cosMid);
435- jacobian[2 ][3 ] = -2 . * halfAngle / tanl;
436- jacobian[2 ][4 ] = 2 . * halfAnglePerQPt;
435+ jacobian[0 ][4 ] = n * halfAnglePerQPt * std::fma (sincDerivative, cosMid, - sinc * sinMid);
436+ jacobian[1 ][4 ] = n * halfAnglePerQPt * std::fma (sincDerivative, sinMid, sinc * cosMid);
437+ jacobian[2 ][3 ] = -2 .f * halfAngle / tanl;
438+ jacobian[2 ][4 ] = 2 .f * halfAnglePerQPt;
437439
438- state.parameters [0 ] += dx ;
439- state.parameters [1 ] += dy ;
440+ state.parameters [0 ] = std::fma (n * sinc, cosMid, state. parameters [ 0 ]) ;
441+ state.parameters [1 ] = std::fma (n * sinc, sinMid, state. parameters [ 1 ]) ;
440442 state.parameters [2 ] = endPhi;
441443 state.referenceCoordinate = targetZ;
442444 return true ;
0 commit comments