Короткий вопрос: определяется ли поведение операторов сравнения с максимальной точностью?
Это означает, что если у меня есть два числа (x и y), которые идентичны с точностью до точности, я должен всегда ожидать один и тот же ответ, когда я делаю x < у?
Я понимаю, что это может показаться глупым вопросом, но позвольте мне остановиться подробнее.
Я работаю с double
и у меня есть массив чисел, как:
0: 62536.5477752959
1: 62536.4840613718
2: 62536.4576412381
3: 62522.8487197062
4: 62536.5473896233
5: 62536.5467941254
6: 62527.3508907998
7: 62536.5477752959
8: 62517.5900098039
9: 62536.5477752959
Обратите внимание, что записи 0, 7 и 9 имеют одинаковое значение.
Когда я делаю (что-то вроде этого):
int low = 0, high = 0;
for(int i = 0; i < N; ++i) {
if(x[i] < x[low])
low = i;
if(x[i] > x[high])
high = i;
}
cout << "low: " << low << " high: " << high << endl;
Я иногда получаю: low: 8 high: 0
иногда: low: 8 high: 7
Я бы ожидал всегда самое низкое значение индекса.
Есть идеи?
[редактировать недостающие скобки.]Да, если предположить IEEE754 для ваших типов с плавающей запятой. Любые два double
ценности x
а также y
скажем таковы, что именно один из x < y
, x == y
, или же x > y
выполняется, за исключением некоторых краевых случаев, таких как + Inf, -Inf или NaN.
Путаница начинает возникать, когда вы используете десятичную запись для представления значений с плавающей запятой; например такого нет double
как 62536.5477752959 (или любой другой в вашем списке в этом отношении).
Числа, которые вы представляете, были усечены вашим отладчиком / стандартным выходом, они не те, которые используются в реальном алгоритме, который вы представляете. Будьте уверены, что такое же десятичное число всегда производит то же самое double
, здесь не делается произвольный выбор: IEEE754 обязывает double
выбран
Для дальнейшего чтения см. Математика с плавающей точкой нарушена?
Наконец, заменить int i
с int i = 0
, В настоящее время поведение вашей программы не определено.
Вы Можно используйте библиотеки, чтобы обойти поведение / ограничения встроенных типов:
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <algorithm>
#include <iostream>
int main() {
using Float = boost::multiprecision::cpp_dec_float_100;
std::vector<Float> values = {
Float{ "62536.5477752959" }, Float{ "62536.4840613718" }, Float{ "62536.4576412381" }, Float{ "62522.8487197062" },
Float{ "62536.5473896233" }, Float{ "62536.5467941254" }, Float{ "62527.3508907998" }, Float{ "62536.5477752959" },
Float{ "62517.5900098039" }, Float{ "62536.5477752959" },
};
auto hilo = std::minmax_element(values.begin(),values.end());
std::cout << "low: " << *hilo.first << " high: " << *hilo.second << std::endl;
}
Печать
low: 62517.6 high: 62536.5
Для печати индексов:
// indexes:
std::cout << "low: " << (hilo.first-values.begin()) << " high: " << (hilo.second-values.begin()) << std::endl;