Семейство функций fmod () дает ужасные результаты.Предположим, вы хотите определить, делится ли 42 на 0,4.Это 105 раз.Тем не менее, fmod выполняет деление и получает результат, подобный 104,9999, который затем округляется до 104, что дает остаток 0,399999, который дает ложноотрицательный результат.remainderl (), однако, похоже, работает.Даже само число 0,4 представляется в точных числах с плавающей запятой.
Для тех, кто не придерживается концепции «деления на равные», это не имеет ничего общего с результатом, являющимся четным числом - у вас, вероятно, есть ваша этимологияв обратном направлении.Четные числа - это те числа, которые делятся на 2 равными частями. И понятие делимости полностью справедливо для нецелых чисел.Равномерно делится означает, что результатом деления является целое число независимо от того, являются ли дивиденд или делитель.Например, если у вас есть металлический токарный станок с ходовым винтом с шагом 3 мм и вырезаете болт с шагом 0,4 мм.14 нитей на 3 мм соответствуют 105 нитям на 0,4 мм.Расчет делимости используется для определения того, где различные движущиеся части токарного станка синхронизируются снова, чтобы вы могли вернуться к следующему проходу резки.Другим примером являются имперские измерения, которые были преобразованы в метрические.50,8 мм (2 дюйма) делится равномерно на 25,4 мм (1 дюйм).Даже без метрических преобразований размеры часто не являются целыми числами, но делимость часто является проблемой: 0,5 "делится на 0,1", 0,125 "и 0,250".Преобразование числа с плавающей запятой (например, 0,375 ") в дробное представление (3/8") является еще одним применением делимости к нецелым числам.
Два альтернативных вычисления в этой функции примера дают одинаковыерезультаты для сотен различных пар чисел.Однако замена remainderl () на fmodl () или roundl () на floorl () дает множество неверных результатов.Я изначально использовал пух 0,001.Фактическая ошибка вычислений обычно имеет порядок 1E-15, поэтому можно использовать меньший пух.Однако сравнение результата с 0.0 даст ложноотрицательный результат.Возможно, вы захотите выразить ваш пух в терминах вашего знаменателя, если вы работаете с очень маленькими числами.делимые (42, 0,4) и делимые (41,0,4) должны давать те же результаты, что и делимые (0,000000042, 0,0000000004) и делимые (0,000000041, 0,0000000004).То есть 42 нм и 41 нм делятся на 0,4 нм?С версией функции, приведенной здесь, они делают.С фиксированным пушком они не обязательно.Однако делимое (42, 0,0000000004) по-прежнему дает ложный отрицательный результат (ошибка составляет 1,53003e-15, что больше, чем размытость 4E-19), поэтому сравнение чисел, отличающихся на 9 порядков, не является надежным.IEEE с плавающей точкой имеет свои ограничения.Обратите внимание, что я использовал длинные двойные вычисления, чтобы минимизировать ошибки вычисления и представления.Эта функция не была протестирована с отрицательными числами.
int divisible(long double a, long double b)
{
int result;
#if 1
if(fabsl(((roundl(a/b)*b)- a)) <= (1E-9*b) ) {
result=TRUE;
} else {
result=FALSE;
}
#else
if( fabsl(remainderl(a,b)) <= (1E-9*b ) ){
result=TRUE;
} else {
result=FALSE;
}
#endif
// printf("divisible(%Lg, %Lg): %Lg, %Lg,%d\n", a, b, roundl(a/b), fabsl(((roundl(a/b)*b)-a)), result);
return(result);
}