#c #precision
#c #точность
Вопрос:
Извините, это ничего не связано с изображением, я просто не знаю, как правильно задать вопрос.
Мой вопрос в том, что я пишу код на C и выполняю вычисления.
a=b*cos(c)
b
изменяется со временем, скажем, от нуля до своей амплитуды bmax
. (на самом деле, b=bmax*sin(t)
.)
Однако я обнаружил, что при b
очень малых значениях результат a
постепенно отклоняется от моих аналитических результатов.
Итак, мне интересно, как сохранить очень высокое разрешение результатов, чтобы избежать отсечения плавающих точек.
Комментарии:
1. Как конкретно постепенно отклоняться? С точки зрения абсолютной ошибки? Относительная ошибка? Как вы вычисляете свою ссылку?
2. Кроме того, является ли тот факт, что это
cos(c)
не имеет значения? Для целей этого вопроса, можем ли мы заменитьcos(c)
наk
?3. Вы используете значения с плавающей запятой или двойные?
4. Я прошу прощения, что это не очень хорошо сформулированный вопрос. Я просто не могу определить по диагонали, в чем проблема. Вы можете видеть из следующего видео, youtu.be/n9bOEr0IAB4
5. Как вы можете видеть, это моделирование CFD, перемещение сетки, перемещение точки сетки из формы rec в форму круглого угла, но после запуска я обнаружил, что она больше не круглая, не зная, в чем проблема. Координаты точек сетки — это просто функция или b * cos (c). Где b — радиус круглого угла, а c — углы точек сетки. Радиус b постепенно меняется со временем. Таким образом, в определенное время значение b было бы очень маленьким. Я не уверен, является ли это проблемой или нет.
Ответ №1:
Когда вы говорите, что оно постепенно отклоняется, это звучит так, как будто у вас накопилось количество ошибок (хотя в опубликованном вами коде нет ничего очевидного). Например, в этом коде ошибка накапливается с каждой итерацией цикла while:
#include <iostream>
int main() {
unsigned short counter;
float val = 0;
while (counter ) {
val = 0.001f;
std::cout << val << "n";
}
}
Где как переписать это, как:
#include <iostream>
int main() {
unsigned short counter;
while (counter ) {
float val = counter * 0.001f;
std::cout << val << "n";
}
}
не вызывает такого накопления ошибок, поскольку val
зависит только от целого числа (которое точно представимо), а не от предыдущих значений, val
каждое из которых внесет некоторую небольшую ошибку.
Комментарии:
1. Спасибо. Поскольку перемещения точек сетки вычисляются таким образом, я не думаю, что это ошибка накопления…. Способ таков: скажем, A — это исходная позиция, B — это новая позиция, B вычисляется из целевой функции, которая должна была быть точной позицией. Таким образом, каждый раз текущая позиция просто «A (B-A)». Итак, я понимаю, что это связано с точностью B’. Вот почему я спросил.
2. Если
A
это старая позиция, аB
это новая позиция, и вы используетеA
(илиB
до ее изменения) при вычислении новой позиции, то у вас будет именно такая ошибка.3. Большое вам спасибо, что, если мне придется поступить первым способом, есть ли другое решение? Я работаю над кодом, который в настоящее время я ничего не могу поделать с его базовыми классами, что означает, что пока мой лучший способ сделать это — предоставить значение (B-A), то есть изменение позиции при каждом временном шаге Delta = B-A. Я понимаю из вашего ответа, что я должен приложить все усилия, чтобы избежать операции сложения или вычитания между небольшим числом и другим небольшим числом. Но пока у меня нет выбора. : (
4. Я надеюсь, что могла бы существовать временно функция высокой точности, чтобы я мог работать таким образом, например a = highPre (b) * cos (c).
5. Если вы можете выразить свою позицию в виде суммы «дельт», вы могли бы использовать суммирование Кахана , чтобы уменьшить ошибку.
Ответ №2:
Другая идея заключается в том, чтобы как можно больше сохранять значения в целых единицах. Конвертируйте только при необходимости.
Пример:
unsigned long value;
const unsigned long scale_factor = 1E6;
// Cosine returns floating point, so convert it to fixed point.
unsigned long temp = cos(c) * scale_factor;
// Reduce propagation of floating point error, by using integral arithmetic.
value = value * temp;
value *= b;
Другой альтернативой является наличие собственных таблиц поиска или интерполяции для случаев, когда дельта очень мала.