Преобразовать миллисекунды в секунды в C

Простой вопрос C, как я могу правильно и лаконично преобразовать миллисекунды в секунды. Есть два ограничения:

  • У меня нет поддержки с плавающей запятой в этом крошечном компиляторе подмножества C
  • Мне нужно, чтобы секунды округлялись до ближайшей секунды (1-499 мс округляются вниз, 500-999 мс округляются вверх. Не нужно заботиться об отрицательных значениях)

    int mseconds = 1600; // should be converted to 2 seconds
    int msec = 23487;  // should be converted to 23 seconds
    

person leeeroy    schedule 18.08.2009    source источник
comment
Как бы вы хотели, чтобы 1500 и 2500 округлялись (подсказка: некоторые другие языки позволяют вам выбрать алгоритм msdn.microsoft.com/en-us/library/system.midpointrounding.aspx)   -  person Rowland Shaw    schedule 18.08.2009


Ответы (3)


Это должно работать

int sec = ((msec + 500) / 1000);
person Chi    schedule 18.08.2009
comment
Это самый чистый способ. Я обычно делаю это, когда у меня есть более 1,6 секунды, чтобы подумать об этом ;-) - person Guss; 18.08.2009
comment
Это предполагает, что: вы округляете от нуля (в отличие от ближайшего четного) в случае ничьей и что вы не округляете отрицательные числа... - person Rowland Shaw; 18.08.2009
comment
В общем: чтобы сделать целочисленное деление с округлением, добавьте половину делимого перед делением. Применяются предостережения Роуленда. - person Laurence Gonsalves; 18.08.2009
comment
@Rowland: Если вы ожидаете отрицательные числа, то это легко объяснить с помощью (мсек‹0?-1:1) * 500 - конечно, это означает больше циклов ЦП, поэтому используйте его только в том случае, если он вам действительно нужен. Аналогичный подход можно использовать для обработки округления к четному. - person Guss; 19.08.2009

Сначала я не хотел писать этот ответ после тестирования на x86, но тестирование на sparc Solaris показало, что он имеет прирост производительности по сравнению с «очевидным решением», так что, возможно, он будет кому-то полезен. Я взял его из файла в формате PDF, который прилагается к книге Восторг хакера. Вот оно:

unsigned msec2sec(unsigned n) {
  unsigned q, r, t;
  n = n + 500;
  t = (n >> 7) + (n >> 8) + (n >> 12);
  q = (n >> 1) + t + (n >> 15) + (t >> 11) + (t >> 14);
  q = q >> 9;
  r = n - q*1000;
  return q + ((r + 24) >> 10);
}

в отличие от:

unsigned msec2sec_obvious(unsigned n) {
  return (n + 500)/1000;
}

На x86 «очевидный алгоритм» преобразуется в добавление 500, а затем длинное умножение на 274877907 с последующим захватом наиболее значимых 32 битов из edx и сдвигом их на 6 бит вправо — так что он превосходит этот код выше без труда (примерно в 5 раз больше производительности разница).

Однако на Solaris/sparc "очевидное" трансформируется в вызов .udiv, что в итоге дает разницу в производительности примерно в 2,5 раза в другом направлении.

person Andrew Y    schedule 18.08.2009

person    schedule
comment
Он прямо сказал, что ему нужно округлить. - person T.J. Crowder; 18.08.2009
comment
Вы, люди, слишком быстры, чтобы минусовать :) Мне потребовалось 20 секунд после того, как я написал, чтобы понять, что округление необходимо, и добавить часть округления, и к тому времени я получил 2 минуса :) - person qrdl; 18.08.2009