Преобразование минут в дни, часы, минуты и секунды

#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 ).