2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу Пред.  1, 2, 3  След.
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 12:35 
На счет моей ошибки. Через арксинус находился наименьший вертикальный угол между прямыми, параллельными данным векторам. Это не совсем то, что нужно.

Думаю, что лучше воспользоваться моей прежней идеей со скалярным произведением (и антикоммутативностью косого произведения).

То есть нужно в моем коде во-первых. добавить функцию DotProduct(), вычисляющую скалярное произведение двух векторов:
Код:
float DotProduct(Vector *First, Vector *Second)
{
    return
        First->x*Second->x
        +First->y*Second->y;
}


Во-вторых, можно выбросить макрос sqr() и переписать функцию Norm():
Код:
float Norm(Vector *Point){return DotProduct(Point,Point);}


Ну и конечно же, исправить функцию Angle():
Код:
/*
**  Calculates a "counterclockwise angle"
**  between two vectors using dot product
**  definition (we allows for wrap around
**  by estimating the exterior product on
**  Cartesian plane).
*/
float Angle(Vector *First, Vector *Second)
{
    float Length, Result=0;

    if(Length=Norm(First)*Norm(Second)) /* Avoid division by zero. */
        Result=acos(DotProduct(First,Second)/sqrt(Length));

    Result*=180/M_PI; /* Convert radians to degrees. */

    /* Wrap around if needed. */
    return ExteriorProduct(First,Second)<0?360-Result:Result;
}


Несколько тестовых случаев:
(3;0), (2;2) -> 45
(2;2), (-3;3) -> 90
(3;0), (2;-2) -> 315
(-1;-1), (0;2) -> 225

Ещё ошибки есть?

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 12:40 
Аватара пользователя
Числа с плавающей точкой лучше не сравнивать на ==.
Вместо
Код:
if (dl==(r1+r2))

Лучше писать
Код:
if (fabs(dl-(r1+r2))<EPS)

предварительно определив EPS как что-нибудь маленькое
Код:
#define EPS 1e-7


Или вообще сделать макрос или инлайн
Код:
#define EQ(x,y) (fabs((x)-(y))<EPS)

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 12:43 
Аватара пользователя
Спасибо, интересное замечание, я тоже об этом думал, но выразить словами так и не смог :))
Код:
if (abs(dl-(r1+r2))<EPS)

Какие бы подобрать примеры на проверку внутреннего касания?
х1, y1, r1 = (1, 1, 1)
x2, y2, r2 = (1, -1, 3)
не подойдет, я понимаю?

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 12:50 
Аватара пользователя
int13 в сообщении #243579 писал(а):
Какие бы подобрать примеры на проверку внутреннего касания?

(x1,y1)=(0,0) r1=1
(x2,y2)=(2,0) r2=3

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 12:53 
Аватара пользователя
Проверку не проходит. Пишет - intersect

Код:
(x1,y1)=(0,0) r1=1
(x2,y2)=(2,0) r2=3

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 12:56 
Аватара пользователя
int13 в сообщении #243581 писал(а):
Проверку не проходит. Пишет - intersect

Мб потому, что проверка на внутреннее касание идет позже проверки на пересечение?

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:04 
Аватара пользователя
Нет, переставил проверку на пересечение в самый низ - ничего не изменилось. Где-то ошибка в формуле.

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:15 
Форматирование ужасное:
Код:
if (dl==0) {
            if (r1>r2) printf("Second circle is embedded in the first.");
            if (r2>r1) printf("First circle is embedded in the second.");
            if (r1==r2) printf("Circles coincide with each other.");
            } else
        if (dl>(r1+r2)) printf("The circles do not interact."); else
        if (dl==(r1+r2)) printf("The circles have one common point. External touch."); else
        if (((r1-r2)<dl)&&(dl<(r1+r2))) printf("The circles intersect."); else
        if ((dl<fabs(r1-r2))  /*&&(dl!=0)*/ &&(r1>r2)) printf("The second circle inside the first."); else
        if ((dl<fabs(r1-r2))  /*&&(dl!=0)*/ &&(r2>r1)) printf("The fisrt circle inside the second."); else
        if ((dl+r2)==r1) printf("The circles have one common point. Internal touch. The second circle inside the first."); else
        if ((dl+r1)==r2) printf("The circles have one common point. Internal touch. The second circle inside the first.");
        printf("\nAgain? ('n' - no, anykey - yes).");

Конструкцию if... else if... else лучше писать так:

Код:
if (foo1)
{
  dosomething();
} else if (foo2)
{
  dosomething2();
} else if (foo3)
{
  dosomething3();
} else
{
  dosomething4();
}


Насчет расстановки скобок не настаиваю, хотя, даже если оператор в скобках только один, их можно опустить, однако это крайне не рекомендуется делать в таких ситуациях. Запрсто можно получить логическую ошибку при вложенных if, хотя компилятор все откомпилирует правильно, например так:
Код:
if (...)
  if (...) foo();
  else if (...) bar();
else (...) foo();

Попробуйте найти эту ошибку, особенно если отформатировано неверно. Так что скобки все-таки расставьте.
Далее - else от if не отделяют новой строкой - нечитабельно абсолютно.
Далее - у Вас конструкция заканчивается на else if, это допустимо, однако, если никакое условие не сработает, программа ничего не выведет. Логичнее было бы закончить так:
Код:
...
else
{
  printf "\nSomething go wrong here";
}


И еще Вы не учли рекомендации использовать double, хотя тут это непринципиально.

-- Вт сен 15, 2009 13:21:36 --

Почему не переделали конструкцию
Код:
if (dl==(r1+r2)) printf("The circles have one common point. External touch.");

аналогично с этой:
Код:
if (fabs(dl-(r1+r2))<EPS) printf("The circles have one common point. Internal touch. The second circle inside the first.");

?

P.S. В педагогических целях (будущим изучающим язык) было неплохо вместо редактирования первого сообщения, публиковать измененный код в новом сообщении. А то вся первая страница уже сейчас стала неактуально, непонятно что обсуждали.

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:21 
2int13
Цитата:
Нет, переставил проверку на пересечение в самый низ - ничего не изменилось. Где-то ошибка в формуле.

Попробуйте поменять окружности местами при вводе данных (сначала введите параметры второй, затем -- первой), если результат изменится -- наверняка ошибка в формуле.

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:22 
Аватара пользователя
int13 в сообщении #243583 писал(а):
Нет, переставил проверку на пересечение в самый низ - ничего не изменилось. Где-то ошибка в формуле

Посмотрел код - вы там написали мое (fabs(dl-(r1+r2))<EPS), а я его приводил для проверки на внешнее касание. Для внутреннего там будет другая разность.

Смысл моего комментария был в том, что за исключением очень небольшого числа случаев, вычисления с типом float или double проводятся с погрешностью, поэтом, например, x*y/y может не совпадать с x или 2.0+3.0 не будет точно равно 5.0
Поэтому при любом сравнении float или double нужно писать не (a==b), а (fabs(a-b)<EPS)

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:25 
2e2e4
Цитата:
И еще Вы не учли рекомендации использовать double, хотя тут это непринципиально.

Ну вы тоже, может быть еще длинную арифметику прикрутить? :) Шучу. Просто, по крайней мере раньше, на олимпиадах по программированию, было важным сэкономить на памяти. Тип double много памяти кушает.

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:32 
Аватара пользователя
Цитата:
И еще Вы не учли рекомендации использовать double

Спасибо, уже учел :)

Цитата:
Где-то ошибка в формуле.

Убрал сравнение с эпсилант - поставил как у меня было в самый первый раз:
Код:
        if ((dl+r2)==r1) printf("The circles have one common point. Internal touch. The second circle inside the first."); else
        if ((dl+r1)==r2) printf("The circles have one common point. Internal touch. The second circle inside the first."); else

Все заработало как нужно. Может нужно как-то по другому сравнивать?
...
Понял в чем ошибка, переделал по другому
...
Теперь появляется:
Код:
hypot: OVERFLOW error

Возможно, после перезапуска это пройдет? С чем это может быть связано?

Цитата:
Форматирование ужасное:

Несколько раз уже слышал такое, но мне почему-то так подсозднательней удобнее. Я конечно понимаю, стандарты, читаемость и все такое, то ли я просто место стараюсь экономить. Вообщем, придется переучиваться видимо :)

Код:
публиковать измененный код в новом сообщении

Я наверно место на форуме экономлю :) Впредь буду перепубликовывать.
Начну прямо сейчас:

код: [ скачать ] [ спрятать ]
Используется синтаксис C
#include <conio.h>
#include <stdio.h>
#include <math.h>
#define EPS (1e-7)

int main()
{
    double x01, x02, y01, y02;
    double r1, r2, dl;
    char ag;
    printf("\nThis program will determine the relative positions of the circles.");

    do
    {
// Input ON
        printf("\nPlease input x-coord of the first circle: ");
        scanf("%f", &x01);
        printf("Please input y-coord of the first circle: ");
        scanf("%f", &y01);
        do
        {
             printf("Please input radius of the first circle: ");
             scanf("%f", &r1);
        } while (r1<=0);
        printf("Please input x-coord of the second circle: ");
        scanf("%f", &x02);
        printf("Please input y-coord of the second circle: ");
        scanf("%f", &y02);
        do
        {
                printf("Please input radius of the second circle: ");
                scanf("%f", &r2);
        } while (r2<=0);
// Input OFF

//        dl=sqrt(((x01-x02)*(x01-x02))+((y01-y02)*(y01-y02)));
        dl=hypot(x01-x02,y01-y02);
        if (dl==0) {
            if (r1>r2) printf("Second circle is embedded in the first.");
            if (r2>r1) printf("First circle is embedded in the second.");
            if (r1==r2) printf("Circles coincide with each other.");
            } else
        if (dl>(r1+r2)) printf("The circles do not interact."); else
        if (fabs(dl-(r1+r2))<EPS) printf("The circles have one common point. External touch."); else
        if ((dl<fabs(r1-r2))  /*&&(dl!=0)*/ &&(r1>r2)) printf("The second circle inside the first."); else
        if ((dl<fabs(r1-r2))  /*&&(dl!=0)*/ &&(r2>r1)) printf("The fisrt circle inside the second."); else
        if ((fabs(dl+r2)-r1)<EPS) printf("The circles have one common point. Internal touch. The second circle inside the first."); else
        if ((fabs(dl+r1)-r2)<EPS) printf("The circles have one common point. Internal touch. The second circle inside the first."); else
        if (((r1-r2)<dl)&&(dl<(r1+r2))) printf("The circles intersect.");
        printf("\nAgain? ('n' - no, anykey - yes).");
        ag=getch();
    } while (ag!='n');
    printf("\nThanks for using.\n");
    return 0;
}


Я и сам не прочь во всяких тонкостях разобраться, так что я с радостью приму все новое :)

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:32 
Код:
#define EPS 1e-7


Обязательно исправьте на
Код:
#define EPS (1e-7)


Гы - чувтсвую скоро получится классная программа. Главное, чтобы автор смог объяснить все тонкости преподавателю.

Еще можно условную компиляцию добавить... :).

Circiter писал(а):
Ну вы тоже, может быть еще длинную арифметику прикрутить? Шучу. Просто, по крайней мере раньше, на олимпиадах по программированию, было важным сэкономить на памяти. Тип double много памяти кушает.

По-моему, на архитектуре IA-32 все вычисления все-равно выполняются с типом double, если у Вас данные хранятся во float, то они занимают-то меньше, а лишняя операция перевода типа - больше процессорного времени. Хотя, скорее всего, это все оптимизируется на уровне компилятора или процессора. А что, данная программа потребляет много памяти? А ограничение на точность уж точно поменьше будет, может быть эту программу будут использовать чтобы рассчитать беспилотную посадку на луну? :)

-- Вт сен 15, 2009 13:34:51 --

int13 писал(а):
Понял в чем ошибка, переделал по другому
...
Теперь появляется:

Код:
hypot: OVERFLOW error

Возможно, после перезапуска это пройдет? С чем это может быть связано?

Так Вы опубликуйте, как Вы переделали!

-- Вт сен 15, 2009 13:40:04 --

А, все увидел.
Кстати с
Код:
#define EPS (1e-7)

Разобрались, почему обязательно в скобочках? Этот вопрос может и преподаватель задать.

-- Вт сен 15, 2009 13:42:39 --

И еще, если Вы находите какую-то ошибку, как в случае с hypot, обязательно пишите данные, которые вводили в программе, чтобы можно было повторить результат.

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:45 
Аватара пользователя
Данные:
(x1,y1)=(0,0) r1=1
(x2,y2)=(2,0) r2=3

Изображение

Код:
#define EPS (1e-7)

Ээ.. Не совсем...

 
 
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:46 
Хе, Вы же тип то поменяли с float на double, а scanf("%f", &x01) и т.д. у Вас читает ввод таки как float! Отсюда и ошибка в hypot - у Вас в переменные типа double записывается значение типа float - в результате там фигня творится.

-- Вт сен 15, 2009 13:50:40 --

Придется либо вернуться к float, либо написать что-то типа:
Код:
float tmp;
scanf("%f", &tmp);
x01 = (double) tmp;

 
 
 [ Сообщений: 42 ]  На страницу Пред.  1, 2, 3  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group