Числовая точность операторов сравнения

Короткий вопрос: определяется ли поведение операторов сравнения с максимальной точностью?
Это означает, что если у меня есть два числа (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
Я бы ожидал всегда самое низкое значение индекса.

Есть идеи?

[редактировать недостающие скобки.]

3

Решение

Да, если предположить IEEE754 для ваших типов с плавающей запятой. Любые два double ценности x а также y скажем таковы, что именно один из x < y, x == y, или же x > y выполняется, за исключением некоторых краевых случаев, таких как + Inf, -Inf или NaN.

Путаница начинает возникать, когда вы используете десятичную запись для представления значений с плавающей запятой; например такого нет double как 62536.5477752959 (или любой другой в вашем списке в этом отношении).

Числа, которые вы представляете, были усечены вашим отладчиком / стандартным выходом, они не те, которые используются в реальном алгоритме, который вы представляете. Будьте уверены, что такое же десятичное число всегда производит то же самое double, здесь не делается произвольный выбор: IEEE754 обязывает double выбран

Для дальнейшего чтения см. Математика с плавающей точкой нарушена?

Наконец, заменить int i с int i = 0, В настоящее время поведение вашей программы не определено.

4

Другие решения

Вы Можно используйте библиотеки, чтобы обойти поведение / ограничения встроенных типов:

Жить на Колиру

#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;
2

По вопросам рекламы [email protected]