Я ищу альтернативу функциям ceil() и floor() в C, поскольку мне не разрешено использовать их в проекте.
То, что я построил до сих пор, представляет собой сложный путь вперед и назад с использованием оператора приведения и с этим преобразованием из значения с плавающей запятой (в моем случае double) в int и позже, поскольку мне нужны ближайшие целые числа, выше и ниже заданного значения с плавающей запятой, чтобы быть также double значениями, обратно к double:
#include <stdio.h>
int main(void) {
double original = 124.576;
double floorint;
double ceilint;
int f;
int c;
f = (int)original; //Truncation to closest floor integer value
c = f + 1;
floorint = (double)f;
ceilint = (double)c;
printf("Original Value: %lf, Floor Int: %lf , Ceil Int: %lf", original, floorint, ceilint);
}
Вывод:
Original Value: 124.576000, Floor Int: 124.000000 , Ceil Int: 125.000000
Для этого примера обычно мне не нужно, чтобы целочисленные значения ceil и floor c и f преобразовывались обратно в double, но они мне нужны в double в моей реальной программе. Считайте это требованием для задачи.
Хотя результат дает желаемые значения и пока кажется правильным, я все еще сомневаюсь, действительно ли этот метод настолько верен и уместен, или, говоря более ясно, если этот метод действительно вызывает какое-либо плохое поведение или проблему в программе или дает мне потерю производительности по сравнению с другими альтернативами, если есть другие возможные альтернативы.
Вы знаете лучшую альтернативу? И если да, то почему этот должен быть лучше?
Большое Вам спасибо.
_mm_round_sd если серьезно — person RobertS supports Monica Cellio schedule 13.12.2019
@Sopel Что мне делать с _mm_round_sd? — person RobertS supports Monica Cellio schedule 13.12.2019
@ RobertS-ReinstateMonica а что, если ввод 124 !!!! — person RobertS supports Monica Cellio schedule 13.12.2019
@ManthanTilva Ну, я думаю, вы правы, я должен предоставить условие, что значение ceil должно быть только + 1 от значения пола, если исходное значение является истинным значением с плавающей запятой. В противном случае значение потолка должно быть эквивалентно значению пола. Для значения пола в этом случае не должно быть существенной разницы. — person RobertS supports Monica Cellio schedule 13.12.2019
@ RobertS-ReinstateMonica: Совершенно верно. Вот что делает выражение 0.0 + i + (f != i) в моем ответе. — person RobertS supports Monica Cellio schedule 13.12.2019
OP’code не работает:
original— это уже целое число.original— это негатив, как и-1.5. Усечения здесь нет.originalнаходится за пределамиintдиапазона.original— это не число.Альтернативное строительство
double my_ceil(double x)Использование приведения к некоторому трюку с целочисленным типом является проблемой, когда
xпревышает размер целочисленного диапазона. Поэтому сначала проверьте, находится лиxв диапазоне достаточно широкого целого числа (точность которого превышаетdouble).xзначения за пределами, которые уже являются целыми числами. Рекомендую использовать самое широкое целое число(u)intmax_t.Помните, что приведение к целому числу — это округление к 0, а не к этажу. Требуется другая обработка, если
xотрицательное / положительное значение, когда кодceil()илиfloor(). Код OP пропустил это.Я бы избегал
if (x >= INTMAX_MAX) {, поскольку это связано с(double) INTMAX_MAX, округление и точное значение которого «выбираются способом, определяемым реализацией». Вместо этого я бы сравнил сINTMAX_MAX_P1.some_integer_MAX— это Число Мерсенна, а с дополнением до 2...MINявляется отрицательной «степенью двойки».Поскольку
xможет быть не числом, более полезно отменить сравнение, как реляционное сравнение NaN неверно.Большое спасибо за подробное объяснение. Да, это то, о чем я просил, так как я просто не знаю всех обстоятельств как новичок. Мне нужно время, чтобы пройти отдельные шаги и разобраться в них в деталях. Большое спасибо, chux! — person RobertS supports Monica Cellio; 14.12.2019
@chqrlie Да, так лучше. — person RobertS supports Monica Cellio; 14.12.2019
Вы упускаете важный шаг: вам нужно проверить, является ли число уже целым, поэтому для
ceil, предполагающего неотрицательные числа (обобщение тривиально), используйте что-то вродеЕще один недостающий элемент в головоломке, который закрывается заключенным мной
if, — это проверить, находится лиfв пределахlong long. На обычных платформах, еслиfнаходился за пределамиlong long, то он в любом случае был бы интегральным.Обратите внимание, что
floorтривиально из-за того, что усечение доlong longвсегда приближается к нулю.Во-первых, большое спасибо за ваш ответ. Почему эти две вещи так важны для дела? Почему плохо, если я их опускаю? Для меня это не так ясно. — person RobertS supports Monica Cellio; 13.12.2019
~ @ RobertS-ReinstateMonica: Версия, которую я представляю, подходит для 64-битных операций с плавающей запятой IEEE754 с двойной точностью. — person RobertS supports Monica Cellio; 13.12.2019
Также существует загадка того, как обрабатывать NaN и бесконечности. — person RobertS supports Monica Cellio; 13.12.2019
@ th33lf: Конечно. Написание портативного
ceil— это боль. Стандартная библиотека C проста в том, что они могут игнорировать переносимость. — person RobertS supports Monica Cellio; 13.12.2019@Bathsheba Какая польза от использования
long long intвместо обычногоintздесь в таком случае? — person RobertS supports Monica Cellio; 13.12.2019@Bathsheba Также: похоже, ваш ответ касается только потолка. Есть ли что-нибудь, что можно улучшить в технике напольного покрытия, как в моем примере? Я не очень доверяю себе, или это неправильные опасения? — person RobertS supports Monica Cellio; 13.12.2019
@ RobertS-ReinstateMonica: Полы более тривиальны, поскольку усечение до
long longвсегда приближается к нулю. — person RobertS supports Monica Cellio; 13.12.2019Но вам все равно следует изменить приведенный выше тест на if (f ‹= — LLONG_MIN || f› = LLONG_MAX) {…. — person RobertS supports Monica Cellio; 13.12.2019
@HansOlsson: работать с отрицательными числами для
ceilне так просто, потому что формула0.0 + i + (f != i)работает только дляf >= 0. Дляf < 0нужно просто использовать(double)i— person RobertS supports Monica Cellio; 14.12.2019@chqrlie — Чтобы обработать это, также обновите оператор возврата, например, return 0.0 + i + (i ‹0? 0.0: (f! = i)); — или другой вариант. В настоящее время код просто говорит, что обрабатывать отрицательные числа тривиально, но не говорит, как это сделать. — person RobertS supports Monica Cellio; 16.12.2019