2014 dxdy logo

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

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




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


26/07/09
1559
Алматы
На счет моей ошибки. Через арксинус находился наименьший вертикальный угол между прямыми, параллельными данным векторам. Это не совсем то, что нужно.

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

То есть нужно в моем коде во-первых. добавить функцию 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 
Заслуженный участник
Аватара пользователя


06/10/08
6422
Числа с плавающей точкой лучше не сравнивать на ==.
Вместо
Код:
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 
Аватара пользователя


05/12/06
126
Нижний Новгород
Спасибо, интересное замечание, я тоже об этом думал, но выразить словами так и не смог :))
Код:
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 
Заслуженный участник
Аватара пользователя


06/10/08
6422
int13 в сообщении #243579 писал(а):
Какие бы подобрать примеры на проверку внутреннего касания?

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

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


05/12/06
126
Нижний Новгород
Проверку не проходит. Пишет - intersect

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

 Профиль  
                  
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 12:56 
Заслуженный участник
Аватара пользователя


06/10/08
6422
int13 в сообщении #243581 писал(а):
Проверку не проходит. Пишет - intersect

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

 Профиль  
                  
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:04 
Аватара пользователя


05/12/06
126
Нижний Новгород
Нет, переставил проверку на пересечение в самый низ - ничего не изменилось. Где-то ошибка в формуле.

 Профиль  
                  
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:15 


21/03/06
1545
Москва
Форматирование ужасное:
Код:
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 
Заслуженный участник


26/07/09
1559
Алматы
2int13
Цитата:
Нет, переставил проверку на пересечение в самый низ - ничего не изменилось. Где-то ошибка в формуле.

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

 Профиль  
                  
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:22 
Заслуженный участник
Аватара пользователя


06/10/08
6422
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 
Заслуженный участник


26/07/09
1559
Алматы
2e2e4
Цитата:
И еще Вы не учли рекомендации использовать double, хотя тут это непринципиально.

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

 Профиль  
                  
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:32 
Аватара пользователя


05/12/06
126
Нижний Новгород
Цитата:
И еще Вы не учли рекомендации использовать 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 


21/03/06
1545
Москва
Код:
#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 
Аватара пользователя


05/12/06
126
Нижний Новгород
Данные:
(x1,y1)=(0,0) r1=1
(x2,y2)=(2,0) r2=3

Изображение

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

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

 Профиль  
                  
 
 Re: Две задачи по Си (1 курс)
Сообщение15.09.2009, 13:46 


21/03/06
1545
Москва
Хе, Вы же тип то поменяли с 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  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group