Есть довольно много проблем с;вначале я отброшу все эти совершенно ненужные скобки, они просто делают код (намного) труднее для чтения:
float* calculateZeros(float p, float q)
{
float *x1, *x2; // pointers are never initialized!!!
if ((p / 2)*(p / 2) - q < 0)
throw std::exception("No Zeros!"); // zeros? q just needs to be large enough!
x1 *= -(p / 2) + sqrt(static_cast<double>((p / 2)*(p / 2) - q);
x2 *= -(p / 2) - sqrt(static_cast<double>((p / 2)*(p / 2) - q);
// ^ this would multiply the pointer values! but these are not initialized -> UB!!!
float returnValue[1];
returnValue[0] = x1; // you are assigning pointer to value here
returnValue[1] = x2;
return x1 != x2 ? returnValue[0] : x1;
// ^ value! ^ pointer!
// apart from, if you returned a pointer to returnValue array, then you would
// return a pointer to data with scope local to the function – i. e. the array
// is destroyed upon leaving the function, thus the pointer returned will get
// INVALID as soon as the function is exited; using it would again result in UB!
}
Так как ваш код даже не скомпилируется ...
Как я вижу, C ++ не поддерживает массивы
Что ж ... Полагаю, вы имели в виду: 'массивы как возвращаемые значения или параметры функции' ,Это верно для необработанных массивов, они могут быть переданы только как указатели.Но вы можете принять структуры и классы в качестве параметров или использовать их в качестве возвращаемых значений.Вы хотите вернуть оба рассчитанных значения?Таким образом, вы можете использовать, например, std::array<float, 2>
;std::array
- это оболочка для необработанных массивов, позволяющая избежать всех хлопот, связанных с последним ... Поскольку существует ровно два значения, вы также можете использовать std::pair<float, float>
или std::tuple<float, float>
.
Хотитебыть в состоянии вернуть 2, 1 или 0 значений?std::vector<float>
может быть вашим выбором ...
std::vector<float> calculateZeros(float p, float q)
{
std::vector<float> results;
// don't repeat the code all the time...
double h = static_cast<double>(p) / 2; // "half"
s = h * h; // "square" (of half)
if(/* s greater than or equal q */)
{
// only enter, if we CAN have a result otherwise, the vector remains empty
// this is far better behaviour than the exception
double r = sqrt(s - q); // "root"
h = -h;
if(/* r equals 0*/)
{
results.push_back(h);
}
else
{
results.reserve(2); // prevents re-allocations;
// admitted, for just two values, we could live with...
results.push_back(h + r);
results.push_back(h - r);
}
}
return results;
}
Теперь остается одна заключительная проблема: так как точность даже двойного ограничена, могут возникнуть ошибки округления (и дело даже стоит, если использовать float; Iрекомендовал бы сделать все числами с плавающей запятой одинаковыми, а также параметры и возвращаемые значения!).Вы никогда не должны сравнивать для точного равенства (someValue
== 0.0), но рассмотрите некоторые эпсилоны, чтобы покрыть плохо округленные значения:
-epsilon < someValue && someValue < +epsilon
Хорошо, в данном случае, есть два первоначально точных сравнениямы могли бы сделать как можно меньше эпсилон-сравнений.Итак:
double d = r - s;
if(d > -epsilon)
{
// considered 0 or greater than
h = -h;
if(d < +epsilon)
{
// considered 0 (and then no need to calculate the root at all...)
results.push_back(h);
}
else
{
// considered greater 0
double r = sqrt(d);
results.push_back(h - r);
results.push_back(h + r);
}
}
Значение эпсилона?Ну, либо используйте исправление, достаточно маленькое значение, либо рассчитайте его динамически на основе меньшего из двух значений (умножьте некоторый небольшой коэффициент на) - и убедитесь, что оно положительное ... Вас может заинтересовать немного больше информация по данному вопросу.Вам не нужно заботиться о том, чтобы не быть C ++ - проблема одинакова для всех языков, использующих представление IEEE754 для двойных чисел.