функции округления в C.
Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Absurd, нас не интересуют краевые значения задачи. Постановка намного проще: есть два соседних пикселя. Задача подсветить тот пиксел, значение которого ближе к данному рациональному значению. Округление даёт в два раза большую точность отображения, чем просто отбрасывание дробной части. Здесь не о чём спорить потому, что это очевидный теоретический факт.
Если для тебя это не очевидно, то ради интереса попробуй нарисовать отрезок прямой попиксельно старым дедовским способом - имея две точки и использую уравнение прямой из школьной геометрии. Нарисуй двумя способами - с отбрасыванием дробной части и с округлением. Тебя сразу же бросится в глаза тот факт, что отрезок второй прямой будет значительно глаже.
Если для тебя это не очевидно, то ради интереса попробуй нарисовать отрезок прямой попиксельно старым дедовским способом - имея две точки и использую уравнение прямой из школьной геометрии. Нарисуй двумя способами - с отбрасыванием дробной части и с округлением. Тебя сразу же бросится в глаза тот факт, что отрезок второй прямой будет значительно глаже.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
Предложи код.Romeo писал(а):Если для тебя это не очевидно, то ради интереса попробуй нарисовать отрезок прямой попиксельно старым дедовским способом - имея две точки и использую уравнение прямой из школьной геометрии. Нарисуй двумя способами - с отбрасыванием дробной части и с округлением. Тебя сразу же бросится в глаза тот факт, что отрезок второй прямой будет значительно глаже.
Я делал так:
[php]
void paintLine(HDC hdc) {
const double theta = 0.5235987756; // 30 degrees
const double cosTheta = cos(theta);
const double sinTheta = sin(theta);
for (int i = 0; i != 1000; ++i) {
double x = double(i)*cosTheta;
double y = double(i)*sinTheta;
SetPixel(hdc, (int)x, (int)y, RGB(0, 0, 0));
}
for (int i = 0; i != 1000; ++i) {
double x = double(i)*cosTheta;
double y = double(i)*sinTheta;
SetPixel(hdc, round(x), round(y) + 50, RGB(0, 0, 0));
}
}
int round(const double& arg) {
if (arg >= 0.0)
return ((int)(arg + 0.5));
else
return ((int)(arg - 0.5));
}
[/php]
Результат вложен
- Вложения
-
- romeo_test.gif (3.99 КБ) 377 просмотров
2B OR NOT(2B) = FF
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Эх, не понять тебе этого. Не писал, зачит, на asm'е под 320*200
Там сразу разница чувствуется
Особенно для более сложных линий: например для окружности.


Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Для прямой, в самом деле, видимо результат будет похож, просто, на самом деле, линия нарисованная одним способом получится чуть смещенной относительно другой "чуть в сторону" (а не только вниз за счет дельты в координате Y).
Вот, кстати, пример с окружностями. В первом случае (отбрасывание целой части) видны "углы" (точки) по "сторонам света" окружности.
Вот, кстати, пример с окружностями. В первом случае (отбрасывание целой части) видны "углы" (точки) по "сторонам света" окружности.
Код: Выделить всё
void CRoundDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
// CDialog::OnPaint();
CPaintDC dc(this); // device context for painting
int i;
const double pi = 3.1415926535;
const int raduis = 100;
int centerX1, centerY, centerX2;
int x1, y1, x2, y2;
double x_, y_;
centerX1 = centerY = 110;
centerX2 = centerX1 + 2 * raduis + 20;
for (i = 0; i < 1000; ++i) {
x_ = raduis * cos (2.0 * pi * i / 1000);
y_ = raduis * sin (2.0 * pi * i / 1000);
x1 = centerX1 + (int)x_;
y1 = centerY + (int)y_;
x2 = centerX2 + round (x_);
y2 = centerY + round (y_);
dc.SetPixel(x1, y1, RGB(0, 0, 0));
dc.SetPixel(x2, y2, RGB(0, 0, 0));
};
}
};
- Вложения
-
- OKR.jpg (34.19 КБ) 377 просмотров
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
Вообще-то обе линии идентичны - обе имеют некрасивые узлы через одинаковый интервал. Можно даже математически доказать что способ округления не влияет на гладкость получаемых фигур при этом алгоритме - тут надо использовать Брезенхайм.Romeo писал(а):Эх, не понять тебе этого. Не писал, зачит, на asm'е под 320*200Там сразу разница чувствуется
Особенно для более сложных линий: например для окружности.
В общем, я ввязался в этот спор потому что цифровая обработка иллюстраций была связана с моим дипломным проектом и я очень упорно в свое время боролся с нузкочастотными муарами которые возникают из-за циклических ошибок округления в double'ах. Способ округления влиял только на фазу муара но ни на его частоту или амплитуду. Пришлось перейти на Рациональные числа из __int64 числителя и такого же знаменателя. В отличие от фиксированной запятой так можно изобразить бесконечные циклические дроби (1/3 например) без потери. Вообще, такие числа можно как угодно умножать и делить без потери разрядов.
2B OR NOT(2B) = FF
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Вот, что и следовало доказать. В случае прямой действительно разницы почти никакой по той причине, что погрешность линейная и уравнение тоже линейное.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
А как можно реализовать округление не просто до целых, а до заданной точности,например, 0,001?
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Умножить 1000, округлить, разделить на 1000.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.