функции округления в C.

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Что-то я затупил.
Какие есть в C функции округления дробного числа до целого? Типа round в Delphi/Pascal.
Т.е. для того, чтобы значение из переменной типа double преобразовать в переменную типа long.
Можно, конечно, просто присвоением (компилятор ругается, но не ошибкой, а варнингом). Или через "преобразование типа":

Код: Выделить всё

 long i;
double dbl;
i = (long)dbl;
Во втором случае даже варнинга нет. Но в обоих случаях значение не округляется, а происходит отсечение дробной части. Т.е. если dbl = 4.5555, то результат получается неа 5, а 4.

Заранее спасибо.
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

в с никто не округляет даблы. а зачем это тебе нужно?
2B OR NOT(2B) = FF
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Absurd, это нужно в милионе случаев. Например при работе с графикой, когда нужно значение коррдинаты, которое хранится в double, округлить к целому, ведь точки на экране дискретные.

BBB, воспользуйся формулой (long)(dSomeDouble + 0.5) - будет работать анологично паскалевскому round.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

Romeo писал(а):Absurd, это нужно в милионе случаев. Например при работе с графикой, когда нужно значение коррдинаты, которое хранится в double, округлить к целому, ведь точки на экране дискретные.

BBB, воспользуйся формулой (long)(dSomeDouble + 0.5) - будет работать анологично паскалевскому round.
Округлять обычно надо только при выводе пользователю в удобоваримом формате и для этого есть sprintf(...).
Для графики совершенно монопенисуально - будешь ли ты отбрасывать дробную часть или делать "математически корректно" - результат будет один и тот же поскольку пикселя бывают только целые.
2B OR NOT(2B) = FF
BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Romeo писал(а):Absurd, это нужно в милионе случаев. Например при работе с графикой, когда нужно значение коррдинаты, которое хранится в double, округлить к целому, ведь точки на экране дискретные.
Ага, именно. Конечно, в таком случае "округление" до целой части вместо округления по математическим правилам не приведет к каким-то фатальным последствиям, но, как говорится, на душе будет теплее, если получится чуть точнее :)
BBB, воспользуйся формулой (long)(dSomeDouble + 0.5) - будет работать анологично паскалевскому round.
Спасибо. Я как-то в этом направлении и стал рассуждать.

Но все равно удивительно, что в C нет такой, казалось бы, базовой арифметической функции.
Absurd писал(а):Для графики совершенно монопенисуально - будешь ли ты отбрасывать дробную часть или делать "математически корректно" - результат будет один и тот же поскольку пикселя бывают только целые.
Странный вывод. Именно потому, что "пикселя бывают только целые" результат отброса дробной части и "округления математически корректно" в статистически половине случаев будет отличаться друг от друга на единицу. Может, как писал выше в этом сообщении, это и не приведет фатальным последствиям, но приятнее чувствовать, что ты получил чуть более точный результат.
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

BBB писал(а):Но все равно удивительно, что в C нет такой, казалось бы, базовой арифметической функции.
Если бы была, то мы бы имели проблесы с каким - нибудь (м)чудаком который бы округлял промежуточный результат и терял разряды.
BBB писал(а):Странный вывод. Именно потому, что "пикселя бывают только целые" результат отброса дробной части и "округления математически корректно" в статистически половине случаев будет отличаться друг от друга на единицу. Может, как писал выше в этом сообщении, это и не приведет фатальным последствиям, но приятнее чувствовать, что ты получил чуть более точный результат.
Нет, более точный результат не получится, поскольку в обоих случаях мы имеем точность до пикселя: либо -0.5 <= x < 0.5 либо 0.0 <= x < 1.0. Это смещение будет компенсировано.
2B OR NOT(2B) = FF
BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Absurd писал(а):Нет, более точный результат не получится, поскольку в обоих случаях мы имеем точность до пикселя: либо -0.5 <= x < 0.5 либо 0.0 <= x < 1.0. Это смещение будет компенсировано.
Эээ.. Признаться, не очень понял, что ты имел в виду. Приведу свой пример.
Пусть "точная" координата (полученная в результате вычисления) равна, скажем, 6.7.
При мат.округлении до целого результат будет 7. При отбрасывании дробной части - 6. Где ошибка (погрешность) больше? Очевидно, что во втором случае.
Таким образом, при мат.округлении значение погрешности всегда будет пределах (по модулю):
0<= погр. <=0.5
А при отбрасывании дробной части в пределах:
0<= погр. < 1
BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Romeo писал(а):BBB, воспользуйся формулой (long)(dSomeDouble + 0.5) - будет работать анологично паскалевскому round.
Пришлось немного тоньше написать:

Код: Выделить всё

long Round (const double &dbl)
{
  if (dbl >= 0)
    return ((long)(dbl + 0.5));
  else
    return ((long)(dbl - 0.5));
};
Если применять просто (long)(dSomeDouble + 0.5), то возникли забавности с отрицательными числами. Например, для -1.4 результат получался 0.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

BBB, с поправкой согласен - я просто принцип показал :) .
Absurd, я тоже не понял твоего примера. Округление даёт меньшую погрешность, чем выделение целой части - это факт. А ты спорить пытаешься :) .
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

BBB писал(а):Эээ.. Признаться, не очень понял, что ты имел в виду. Приведу свой пример.
Пусть "точная" координата (полученная в результате вычисления) равна, скажем, 6.7.
При мат.округлении до целого результат будет 7. При отбрасывании дробной части - 6. Где ошибка (погрешность) больше? Очевидно, что во втором случае.
Объяснаю на пальцах. При отбрасывании дробной части крайний левый пиксель имеет покрытие значений 0.0 <= x < 1.0. При округлении к ближайшему целому - 0.0 <= x < 0.5. В то время как второй пиксель имеет покрытие в два раза шире : 0.5 <= x < 1.5. Если же поместить "(0 , 0)" координатной сетки в центр окна то ситуация не изменится так как ты уже заметил что отбрасывание дробной части у -0.5 дает -1.
2B OR NOT(2B) = FF
Ответить