Когда я выполняю этот код, значение ans1, ans2 равно 50002896 и 50005000. Я знаю, что есть некоторые проблемы с функцией ceil, но не смог выяснить точную причину.
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long ans1 = 0, ans2 = 0;
for (long long i = 1; i <= 10000; i++)
{
ans1 = ans1 + ceil((float)i / 1);
ans2 = ans2 + i;
}
cout << ans1 << " " << ans2 << endl;
}
Наверное, это из-за (float), а не из-за ceil. float не совсем точно.
Не используя надлежащие стандартные заголовочные файлы, а также используя using namespace std;, не зная, что извлекает этот нестандартный заголовочный файл, мы не знаем, является ли он std::ceil или ceil из библиотеки времени выполнения C. Вот почему использование bits...whatever — плохая идея, не говоря уже о том, что это нестандартно.
@PaulMcKenzie Без заголовка cmath компиляция завершается с ошибкой с флагами c++11, c++14, c++17 и c++20: ошибка: «ceil» не является членом «std» — я не уверен, чем отличаются ceil() и std::ceil().
@RohanBari Нет гарантии компиляции, если вы не включите правильные заголовочные файлы.
@PaulMcKenzie Примечание: использование ceil(без std::) также может привести к разным результатам в зависимости от импорта <cmath> или <math.h>
@Ranoiaetep - Да, поэтому использование нестандартного заголовка «включить все» проблематично.
@Chinnmay B S Почему float используется ceil((float)i / 1) вместо double или long double?
Кроме того, вместо использования ceil((some_float / 1)) для преобразования числа с плавающей запятой в целое число используйте вместо этого std::lround и std::llround.
Источником проблемы является не функция ceil, а то, что не все целые числа могут быть точно представлены в виде значений с плавающей запятой.
Еще немного информации о представлении с плавающей запятой: Википедия IEEE 754 . И связанный пост: Какое первое целое число, которое число с плавающей запятой IEEE 754 не может точно представить?.
Следующий код является минимальной демонстрацией той же проблемы, которая вызывает вашу проблему:
float f1 = 100000000;
f1++;
std::cout << std::to_string(f1) << std::endl;
[Неверно] Вывод (ожидаемый: +1):
100000000.000000
Один из подходов — использовать double вместо float. Это не решит основную проблему, но значительно увеличит диапазон представляемых целых чисел:
double f1 = 100000000;
f1++;
std::cout << std::to_string(f1) << std::endl;
Вывод:
100000001.000000
Некоторые примечания:
#include <bits/stdc++.h>
- см. здесь: Почему я не должен #include <bits/stdc++.h>?.using namespace std
- см. здесь Почему "using namespace std;" считается плохой практикой?.Во-первых, попробуйте использовать определенные заголовки, такие как #include , в этом случае .because #include <bits/stdc++.h> принесет много мусора.
Итак, проблема с float, а не с ceil, описанная ниже
Значения с плавающей запятой не представляют точные значения.
Код:-
#include <iostream>
#include <iomanip>
using namespace std;
// Driver Code
int main()
{
float num1 = 10000.29;
float num2 = 10000.2;
// Output should be 0.0900000000
cout << std::setprecision(15)
<< (num1 - num2);
return 0;
}
Вывод :-
0.08984375
#include <bits/stdc++.h>
-- Включите правильные файлы заголовков, а не этот.