Преобразование в float в расчете uint32_t

Я пытаюсь улучшить SWRTC, изменив определение секунды (длинный беззнаковый n_ticks_per_second), синхронизируя время с сервером.

#include <stdint.h>
#include <stdio.h>

int main(int argc, char * argv[]){

    int32_t total_drift_SEC;
    int32_t drift_per_sec_TICK;
    uint32_t at_update_posix_time = 1491265740;
    uint32_t posix_time = 1491265680;
    uint32_t last_update_posix_time = 1491251330;
    long unsigned n_ticks_per_sec = 1000;

    total_drift_SEC = (posix_time - at_update_posix_time);
    drift_per_sec_TICK = ((float) total_drift_SEC) / (at_update_posix_time - last_update_posix_time);

    n_ticks_per_sec += drift_per_sec_TICK;

    printf("Total drift sec %d\r\n", total_drift_SEC);
    printf("Drift per sec in ticks %d\r\n", drift_per_sec_TICK);
    printf("n_ticks_per_second %lu\r\n", n_ticks_per_sec);

    return 0;

}

Чего я не понимаю, так это того, что мне нужно приводить total_drift_SEC для плавания, чтобы в конце получить правильный результат, т. Е. Иметь n_ticks_per_sec равным 1000 в конце.

Выход этого кода:

Общий дрейф сек -60

Дрейф в секунду в тиках 0

n_ticks_per_second 1000

Принимая во внимание, что вывод кода без приведения к float:

Общий дрейф сек -60

Дрейф в секунду в тиках 298054

n_ticks_per_second 299054

2 ответа

Решение

Эта линия

drift_per_sec_TICK = total_drift_SEC / (at_update_posix_time - last_update_posix_time);

делит 32 бит signed int 32 бит unsigned int,

32 бит unsigned int имеет более высокий ранг, чем 32-битный signed int,

При выполнении арифметических операций применяются "Обычные арифметические преобразования":

Из стандарта С11 (проект) 6.3.1.8/1:

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

Так -60 преобразуется в (32 бит) unsigned int: 4294967236

Вот

drift_per_sec_TICK = (float) total_drift_SEC / (at_update_posix_time - last_update_posix_time);

Применяется следующее (из параграфа стандарта С, как указано выше):

если соответствующий действительный тип одного из операндов является плавающим, другой операнд преобразуется без изменения домена типа в тип, соответствующий действительный тип которого float,


Чтобы не слепо входить в эти ловушки, всегда указывайте -Wconversion при компиляции с GCC.

Потому что с "целочисленной" версией total_drift_SEC станет unsigned так -60 -> 4294967236

4294967236 / 14410 = 298054

Используя float, подразделение рассчитает:

-60/14410 = 0

См. Стандарт c на стр. 53.

6.3.1.8 Обычные арифметические преобразования

1 Многие операторы, которые ожидают операнды арифметического типа, вызывают преобразования и выдают типы результатов аналогичным образом. Цель состоит в том, чтобы определить общий реальный тип для операндов и результата. Для указанных операндов каждый операнд преобразуется без изменения типа домена в тип, соответствующий действительный тип которого является общим действительным типом. Если явно не указано иное, общий действительный тип также является соответствующим действительным типом результата, чья область типов является областью типов операндов, если они одинаковы, и сложной в противном случае. Этот шаблон называется обычными арифметическими преобразованиями: [...] В противном случае целочисленные преобразования выполняются для обоих операндов. Затем к повышенным операндам применяются следующие правила:

  • Если оба операнда имеют одинаковый тип, дальнейшее преобразование не требуется. В противном случае, если оба операнда имеют целочисленные типы со знаком или оба имеют целочисленные типы без знака, операнд с типом ранга преобразования с меньшим целым числом преобразуется в тип операнда с большим рангом.
  • В противном случае, если операнд с целым типом без знака имеет ранг, больший или равный рангу типа другого операнда, тогда операнд с целым типом со знаком преобразуется в тип операнда с целым типом без знака.
  • В противном случае, если тип операнда с целочисленным типом со знаком может представлять все значения типа операнда с целочисленным типом без знака, тогда операнд с целочисленным типом без знака преобразуется в тип операнда с целочисленным типом со знаком.
  • В противном случае оба операнда преобразуются в тип целого без знака, соответствующий типу операнда с целым типом со знаком.

Эфазис мой

Другие вопросы по тегам