После некоторых экспериментов, я думаю, что могу дать частичный ответ.Позвольте мне перефразировать вопрос: Напишите функцию
int bin(double x, double m)
, вычисляющий
int(floor(x/m))
точно. Предположим, m положительный и что результат находится в диапазоне int.
Первая попытка
int bin0(double x, double m) {
return int(std::floor(x/m));
}
, но это не удается для случая м = 360,0 и х = -denorm_min (0 возвращается вместо -1).
Поскольку эта неудача только для х близко к нулю, то вторая попытка
int bin1(double x, double m) {
int n = int(std::floor(x/m));
return n == 0 && x < 0 ? -1 : n;
}
Я верю это возвращает точный ответ при условии что п * м является точно представляемый как двойной. Для m = 360,0 включает в себя все n представляется в виде 32-разрядного целого. Я прав? Доказательством будет приятно!
Если это условие не выполняется, например, м = 0,1, то лучшее, что я могу придумать является
int bin2(double x, double m) {
double z = std::fmod(x, m);
return int(std::floor((x - z)/m + 0.5)) + (z < 0 ? -1 : 0);
}
ли это всегда возвращает правильный результат? Есть ли некоторые «чистые» решения ?
ADDENDUM: В моем приложении мне нужно было получить только четность номера ячейки (четного или нечетного). (Мое приложение измеряет площадь геодезического многоугольника , и мне нужно отслеживать, охватывает ли край полюс четное или нечетное число раз.) Поэтому предложение chux использовать remquo является хорошим. К сожалению (1) std :: remquo требует C++ 11 и (2) более серьезно, реализация glibc remquo является ошибкой; см. это bug report. Так что я в конечном итоге делает по существу
int binparity(real x, real m) {
// return the parity of int(floor(x/m))
x = std::fmod(x, 2 * m);
return (x >= 0 && x < m) || x < -m ? 0 : 1
}
К сожалению, неравенство п * 360 - d <п * 360 должен был быть истолковано как «то, что вы получите, если вы сделали все операции с использованием арифметики с плавающей точкой». Таким образом, при достаточно малых d, например, 1.0e-30, , неравенство выполняется только при n = 0 (с использованием double). Я отредактирую на вопрос, чтобы уточнить. – cffk
Перейдем к проблеме более высокого уровня: «для учета пересечений простого меридиана точно» В 'C', а не использовать' y = n * 360 - d; 'для некоторого' n', используйте 'longitude = fmod (долгота, 360.0); 'и терпеть _no_ потерю точности независимо от' долготы'. [ref] (http://stackoverflow.com/questions/20928253/is-fmod-exact-when-y-is-an-integer) – chux
Да, я уже использую это (и мне приходится иметь дело с досадной проблемой, которая результат может лежать в (-360,360)).В моем текущем приложении мне нужно определить, какой период долготы я нахожу, т. Е. Пол (долгота/360). – cffk