/*! \brief * Converts a floating point value to integer. * * \param[in] n Number of values in the \p val->u array. * \param[in,out] val Value to convert. * \param[in] cmpt Comparison operator type. * \param[in] bRight true if \p val appears on the right hand size of * \p cmpt. * \returns 0 on success, EINVAL on error. * * The values are rounded such that the same comparison operator can be used. */ static void convert_real_int(int n, t_compare_value *val, e_comparison_t cmpt, bool bRight) { int i; int *iv; if (!bRight) { cmpt = reverse_comparison_type(cmpt); } snew(iv, n); /* Round according to the comparison type */ for (i = 0; i < n; ++i) { switch (cmpt) { case CMP_LESS: case CMP_GEQ: iv[i] = static_cast<int>(std::ceil(val->r[i])); break; case CMP_GTR: case CMP_LEQ: iv[i] = static_cast<int>(std::floor(val->r[i])); break; case CMP_EQUAL: case CMP_NEQ: sfree(iv); /* TODO: Implement, although it isn't typically very useful. * Implementation is only a matter of proper initialization, * the evaluation function can already handle this case with * proper preparations. */ GMX_THROW(gmx::NotImplementedError("Equality comparison between dynamic integer and static real expressions not implemented")); case CMP_INVALID: /* Should not be reached */ sfree(iv); GMX_THROW(gmx::InternalError("Invalid comparison type")); } } /* Free the previous value if one is present. */ sfree(val->i); val->i = iv; val->flags &= ~CMP_REALVAL; val->flags |= CMP_ALLOCINT; }
/* \brief * Converts a floating point value to integer. * * \param[in] n Number of values in the \p val->u array. * \param[in,out] val Value to convert. * \param[in] cmpt Comparison operator type. * \param[in] bRight TRUE if \p val appears on the right hand size of * \p cmpt. * \returns 0 on success, EINVAL on error. * * The values are rounded such that the same comparison operator can be used. */ static int convert_real_int(int n, t_compare_value *val, e_comparison_t cmpt, gmx_bool bRight) { int i; int *iv; if (!bRight) { cmpt = reverse_comparison_type(cmpt); } snew(iv, n); /* Round according to the comparison type */ for (i = 0; i < n; ++i) { switch (cmpt) { case CMP_LESS: case CMP_GEQ: iv[i] = (int)ceil(val->r[i]); break; case CMP_GTR: case CMP_LEQ: iv[i] = (int)floor(val->r[i]); break; case CMP_EQUAL: case CMP_NEQ: fprintf(stderr, "comparing equality an integer expression and a real value\n"); sfree(iv); return EINVAL; case CMP_INVALID: /* Should not be reached */ gmx_bug("internal error"); sfree(iv); return EINVAL; } } /* Free the previous value if one is present. */ sfree(val->i); val->i = iv; val->flags &= ~CMP_REALVAL; val->flags |= CMP_ALLOCINT; return 0; }
static void init_compare(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data) { t_methoddata_compare *d = (t_methoddata_compare *)data; int n1, n2; /* Store the values */ n1 = init_comparison_value(&d->left, ¶m[0]); n2 = init_comparison_value(&d->right, ¶m[3]); /* Store the comparison type */ d->cmpt = comparison_type(d->cmpop); if (d->cmpt == CMP_INVALID) { GMX_THROW(gmx::InternalError("Invalid comparison type")); } /* Convert the values to the same type */ /* TODO: Currently, there are no dynamic integer-valued selection methods, * which means that only the branches with convert_int_real() will ever be * taken. It should be considered whether it is necessary to support these * other cases at all. */ if ((d->left.flags & CMP_REALVAL) && !(d->right.flags & CMP_REALVAL)) { if (d->left.flags & d->right.flags & CMP_DYNAMICVAL) { /* Nothing can be done */ } else if (!(d->right.flags & CMP_DYNAMICVAL)) { convert_int_real(n2, &d->right); } else /* d->left is static */ { convert_real_int(n1, &d->left, d->cmpt, false); } } else if (!(d->left.flags & CMP_REALVAL) && (d->right.flags & CMP_REALVAL)) { if (d->left.flags & d->right.flags & CMP_DYNAMICVAL) { /* Reverse the sides to place the integer on the right */ int flags; d->left.r = d->right.r; d->right.r = NULL; d->right.i = d->left.i; d->left.i = NULL; flags = d->left.flags; d->left.flags = d->right.flags; d->right.flags = flags; d->cmpt = reverse_comparison_type(d->cmpt); } else if (!(d->left.flags & CMP_DYNAMICVAL)) { convert_int_real(n1, &d->left); } else /* d->right is static */ { convert_real_int(n2, &d->right, d->cmpt, true); } } }
/*! * \param[in] top Not used. * \param[in] npar Not used (should be 5). * \param[in] param Method parameters (should point to \ref smparams_compare). * \param[in] data Should point to a \c t_methoddata_compare. * \returns 0 if the input data is valid, -1 on error. */ static int init_compare(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data) { t_methoddata_compare *d = (t_methoddata_compare *)data; int n1, n2; /* Store the values */ n1 = init_comparison_value(&d->left, ¶m[0]); n2 = init_comparison_value(&d->right, ¶m[3]); if (n1 == 0 || n2 == 0) { gmx_bug("one of the values for comparison missing"); return -1; } /* Store the comparison type */ d->cmpt = comparison_type(d->cmpop); if (d->cmpt == CMP_INVALID) { gmx_bug("invalid comparison type"); return -1; } /* Convert the values to the same type */ if ((d->left.flags & CMP_REALVAL) && !(d->right.flags & CMP_REALVAL)) { if (d->left.flags & d->right.flags & CMP_DYNAMICVAL) { /* Nothing can be done */ } else if (!(d->right.flags & CMP_DYNAMICVAL)) { convert_int_real(n2, &d->right); } else /* d->left is static */ { if (convert_real_int(n1, &d->left, d->cmpt, FALSE)) { return -1; } } } else if (!(d->left.flags & CMP_REALVAL) && (d->right.flags & CMP_REALVAL)) { if (d->left.flags & d->right.flags & CMP_DYNAMICVAL) { /* Reverse the sides to place the integer on the right */ int flags; d->left.r = d->right.r; d->right.r = NULL; d->right.i = d->left.i; d->left.i = NULL; flags = d->left.flags; d->left.flags = d->right.flags; d->right.flags = flags; d->cmpt = reverse_comparison_type(d->cmpt); } else if (!(d->left.flags & CMP_DYNAMICVAL)) { convert_int_real(n1, &d->left); } else /* d->right is static */ { if (convert_real_int(n2, &d->right, d->cmpt, TRUE)) { return -1; } } } return 0; }