#c
#c
Вопрос:
Я нахожусь в классе C начального уровня, и у меня возникли некоторые проблемы с выяснением, почему я получаю неверный результат при преобразовании минут в дни, часы, минуты и секунды в C .
Мне помогла подруга, и она смогла получить правильный вывод в Python, используя ту же математику, но по какой-то причине в C я не могу получить правильный вывод для секунд. Я уверен, что есть гораздо более простой способ получить выходные данные, но профессор хочет, чтобы мы написали это именно так.
Например, входные данные будут равны 10,5, а код выводит 0d 0h 10m 0s вместо 0d 0h 10m 30s.
Вот код:
#include <iostream>
using namespace std;
int main() {
//get the starting number of minutes
int inputMinutes;
double decimalMinutes;
cout << "Enter number of minutes: ";
cin >> decimalMinutes;
//allow decimal input
inputMinutes = decimalMinutes;
//get number of days
int days = inputMinutes / 1440;
inputMinutes = inputMinutes % 1440;
//get number of hours
int hours = inputMinutes / 60;
//get number of minutes
int mins = inputMinutes % 60;
int seconds = inputMinutes % 1 * 60;
//output days, hours, minutes and seconds
cout << days << "d " << hours << "h " << mins << "m " << seconds << "s" << endl;
}
У меня такое чувство, что это как-то связано с преобразованием int в double, но если это не так, то я не уверен, что с этим может быть не так. Любая помощь приветствуется, спасибо.
Комментарии:
1. Вот где вы теряете свои секунды:
inputMinutes = decimalMinutes;
.2. Вы не можете
cin >> decimalMinutes
?3. Вам повезло, что 0.5 может быть представлено точно как double. Если вы попытаетесь использовать другое значение, например, maybe
10.33
, не удивляйтесь, если проблемы с округлением приведут к неправильным ответам.4. Мне помогла подруга, и она смогла получить правильный вывод на Python — Python — это не C . Что бы ни сделал ваш друг, это может быть неприменимо к программе на C .
5. Когда я удаляю inputMinutes = decimalMinutes; он вообще не выводит никаких значений.
Ответ №1:
Как уже указывали другие пользователи, когда вы пишете, inputMinutes = decimalMinutes;
вы преобразуете double
в int
, теряя всю информацию о десятичной части. Вы должны отделить эту часть от целочисленной части вашей decimalMinutes
переменной, затем умножить ее на 60, чтобы получить секунды. Смотрите приведенный ниже код.
#include <iostream>
int main() {
//get the starting number of minutes
int inputMinutes;
double decimalMinutes;
double decPart;
std::cout << "Enter number of minutes: ";
std::cin >> decimalMinutes;
//allow decimal input
inputMinutes = decimalMinutes;
decPart = decimalMinutes-inputMinutes;
//get number of days
int days = inputMinutes / 1440;
inputMinutes = inputMinutes % 1440;
//get number of hours
int hours = inputMinutes / 60;
//get number of minutes
int mins = inputMinutes % 60;
int seconds = decPart * 60;
//output days, hours, minutes and seconds
std::cout << days << "d " << hours << "h " << mins << "m " << seconds << "s" << std::endl;
return 0;
}
Это должно сработать: вот некоторые из моих результатов.
Enter number of minutes: 10.5
0d 0h 10m 30s
Enter number of minutes: 126.3333333
0d 2h 6m 19s
Enter number of minutes: 1440.4
1d 0h 0m 24s
Enter number of minutes: 12.1
0d 0h 12m 5s
Вы видите, что все еще существуют некоторые проблемы с округлением (если вы хотите вычислить 1/3 минуты, вы должны ввести периодическое число 0.3333333333 …, а представление 0.1 является периодическим в арифметике с плавающей запятой), и это связано с тем, как обрабатывается преобразование из double
в int
(см. Комментарий @PaulMcKenzie к вашему ответу).
Комментарии:
1. 1/3 минуты — это 20 секунд. 1/3 не равно 0,3
2. @Mestkon вы правы, я не был точным. Я приведу более значимые примеры, чтобы прояснить свою точку зрения.
Ответ №2:
Проблема с использованием целого числа. Измените inputMinutes на double и используйте fmod. Этот код должен работать.
#include <iostream>
#include <math.h>
using namespace std;
int main() {
//get the starting number of minutes
double inputMinutes;
double decimalMinutes;
cout << "Enter number of minutes: ";
cin >> decimalMinutes;
//allow decimal input
inputMinutes = decimalMinutes;
//get number of days
int days = inputMinutes / 1440;
inputMinutes = fmod(inputMinutes,1440);
//get number of hours
int hours = inputMinutes / 60;
//get number of minutes
int mins = fmod(inputMinutes,60);
int seconds = fmod(inputMinutes,1) * 60;
//output days, hours, minutes and seconds
cout << days << "d " << hours << "h " << mins << "m " << seconds << "s" << endl;
}
Комментарии:
1. Я не думаю, что так много вызовов
fmod()
необходимо. Проще просто умножить ввод на 60, преобразовать вint
илиlong
, а затем работать с целочисленными секундами.2. Я не уверен, что такое fmod, но он специально заявил, что, даже если бы мы знали C , он хотел, чтобы лабораторная работа была выполнена только с материалом, который мы рассмотрели.
3. @Slava Итак, я должен по существу преобразовать минуты в секунды, а затем преобразовать секунды во все остальное впоследствии?
4. @efan Fmod просто по модулю, но возвращает значение с плавающей точкой. Но достаточно справедливо, если вы можете использовать только то, что вы узнали. Идея Славы должна сработать.
Ответ №3:
В качестве альтернативы самостоятельному хранению соотношений между числами вы могли бы использовать определения в std::chrono
пространстве имен.
#include <iostream>
#include <chrono>
using f_minutes = std::chrono::duration<double, std::chrono::minutes::period>;
int main() {
//get the starting number of minutes
double input;
std::cout << "Enter number of minutes: ";
std::cin >> input;
f_minutes decimalMinutes(input);
auto days = duration_cast<std::chrono::days>(decimalMinutes);
decimalMinutes -= days;
auto hours = duration_cast<std::chrono::hours>(decimalMinutes);
decimalMinutes -= hours;
auto mins = duration_cast<std::chrono::minutes>(decimalMinutes);
decimalMinutes -= mins;
auto seconds = duration_cast<std::chrono::seconds>(decimalMinutes);
//output days, hours, minutes and seconds
std::cout << days.count() << "d " << hours.count() << "h " << mins.count() << "m " << seconds.count() << "s" << std::endl;
}
Ответ №4:
Поскольку вам не нужны доли секунды, вы могли бы просто пойти путем умножения вашего ввода на 60, а затем перейти ко всем целым числам:
int main() {
int inputSeconds; // << I changed this to seconds here
double decimalMinutes;
cout << "Enter number of minutes: ";
cin >> decimalMinutes;
inputSeconds = 60.*decimalMinutes; // << times 60, now contains the seconds as a whole number
int days = inputSeconds / (1440*60); // I do a multiplication here to make it clear for you what is happening
...
}
Обратите внимание, что преобразование из двойного в целое число по существу округляет в меньшую сторону. Например, (int) 0.9
равно нулю. Если вы хотите округлить до ближайшего числа, нам придется пойти более сложным путем.
Кроме этого, я настоятельно рекомендую вам прочитать руководство по использованию отладчика. Если бы вы использовали его, вы бы увидели, что ваша переменная потеряла некоторые данные.
В качестве альтернативы или дополнительно узнайте, как выполнять отладку с использованием консольных сообщений ( std::cout
).