Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> класс Rectangle, Погрешность вычисления косинуса Оо? 
:(
    Опции темы
BrAgOl
Дата 16.9.2011, 08:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 6.3.2005
Где: М.О.

Репутация: нет
Всего: нет



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

с Первым пунктом все ясно, со вторым вроде бы тоже. Тут загвоздка в проверке получится ли прямоугольник или нет. Решил проверить на равенство диагоналей и на равенства косинусов противоположных углов друг другу и соответственно нулю.
Задал заранее "правильные координаты" диагонали равны, а косинусы получаются приблизительно 0,07, судя по всему это погрешность, но мне она показалось слишком большой, если бы речь шла о тысячных еще ничего... Я взял, что точки задаются парами, начиная с левого нижнего угла и по часовой стрелке
вот собственно код:

.h:
Код

#ifndef RECT_H
#define RECT_H


class Rect
{
    public:
        Rect( double = 1, double = 1 );
        void setLength( double );
        void setWidth( double );
        double getArea();
        double getPerimetr();
        double getLength() { return length; };
        double getWidth() { return width; };
        //************************************************************
        Rect ( double, double, double, double, double, double, double, double );
        void setDecRect( double, double, double, double, double, double, double, double );
        //void setDecWidth( double, double, double, double );


    private:
        double length;
        double width;
        double area;
        double perimetr;
        double x1, y1, x2, y2, x3, y3, x4, y4, COS1, COS2, d1, d2;
};

#endif // RECT_H


.cpp:
Код

#include "Rect.h"
#include <iostream>
#include <windows.h>
#include <math.h>

using namespace std;

Rect::Rect( double l, double w )
{
    setLength( l );
    setWidth( w );
}
void Rect::setLength( double l )
{
    length = l;
    if( length <= 0 || length > 20 )
    {
        cout << "ERROR! ENTER NEW DATA.\n";
        exit(1);
    }

}
void Rect::setWidth( double w )
{
    width = w;
    if( width <= 0 || width > 20 )
    {
        cout << "ERROR! ENTER NEW DATA.\n";
        exit(1);
    }
}
double Rect::getArea()
{
    area = length * width;
    return area;
}
double Rect::getPerimetr()
{
    perimetr = ( length + width ) * 2;
    return perimetr;
}


//*******************************************************************


Rect::Rect ( double x_1, double y_1, double x_2, double y_2, double x_3, double y_3, double x_4, double y_4 )
{
    setDecRect( x_1, y_1, x_2, y_2, x_3, y_3, x_4, y_4 );
    //setDecWidth( x_3, y_3, x_4, y_4 );
}

void Rect::setDecRect( double x_1, double y_1, double x_2, double y_2, double x_3, double y_3, double x_4, double y_4 )
{
    double d_1, d_2, l, w, COSlw, l1,w1, COSl1w1;
    if( x_1 <= 0 || x_2 <= 0 || y_1 <= 0 || y_2 <= 0 || x_3 <= 0 || x_4 <= 0 || y_3 <= 0 || y_4 <= 0 )
    {
        cout << "\nERROR! THE ENTERED POINTS ARE NEGATIVE. ENTER NEW DATA.\n";
        exit(1);
    }
    else
    {
        x1 = x_1;
        y1 = y_1;

        x2 = x_2;
        y2 = y_2;

        x3 = x_3;
        y3 = y_3;

        x4 = x_4;
        y4 = y_4;

        d_1 = sqrt( pow( ( x4 - x2 ), 2 ) + pow( ( y4 - y2 ), 2 ) );
        d_2 = sqrt( pow( ( x3 - x1 ), 2 ) + pow( ( y3 - y1 ), 2 ) );
        l = sqrt( pow( ( y2 - y1 ), 2 ) + pow( ( x2 - x1 ), 2 ) );
        w = sqrt( pow( ( y4 - y1 ), 2 ) + pow( ( x4 - x1 ), 2 ) );
        COSlw = ( ( l*l + w*w - d_1*d_1 ) / ( 2 * l*l*w*w) );
        l1 = sqrt( pow( ( y4 - y3 ), 2 ) + pow( ( x4 - x3 ), 2 ) );
        w1 = sqrt( pow( ( y3 - y2 ), 2 ) + pow( ( x3 - x2 ), 2 ) );
        COSl1w1 = ( ( l1*l1 + w1*w1 - d_1*d_1 ) / ( 2 * l1*l1*w1*w1) );

        COS1 = COSlw;
        COS2 = COSl1w1;
        d1 = d_1;
        d2 = d_2;

    }
    if( d1 == d2 && COS1 == COS2 && COS1 == 0 )
    {
        length = l;
        width = w;
    }
    else
    {
        cout << "\n\n\nERROR! THE ENTERED POINTS ARE ILLEGAL. ENTER NEW DATA.\n" << "COS1 = " << COS1 << " COS2 = " << COS2
        << " D1 = " << d1 << " D2 = " << d2 << "\n\n\n";
        exit(1);
    }
}




main:
Код

#include <iostream>
#include <windows.h>
#include "Rect.h"

using namespace std;

int main()
{
    Rect R( 5.33, 9.45 );
    cout << "Yoy create the rectangle with length = " << R.getLength() << "\nand with width = " << R.getWidth()
    << "\nPerimetr = " << R.getPerimetr() << "\nArea = " << R.getArea();

    Rect RR( 2, 4, 2, 7, 7, 4, 7, 7 );
    cout << "Yoy create the rectangle with length = " << RR.getLength() << "\nand with width = " << RR.getWidth()
    << "\nPerimetr = " << RR.getPerimetr() << "\nArea = " << RR.getArea();
    return 0;
}



Это сообщение отредактировал(а) BrAgOl - 16.9.2011, 14:03
PM MAIL   Вверх
volatile
Дата 16.9.2011, 10:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(BrAgOl @  16.9.2011,  08:59 Найти цитируемый пост)
 а косинусы получаются приблизительно 0,07,

Это еще повезло, здесь косинус может быть равен вообще чему угодно
Цитата(BrAgOl @  16.9.2011,  08:59 Найти цитируемый пост)
       COSlw = ( ( l*l + w*w - d1*d1 ) / ( 2 * l*l*w*w) );

d1 - содержат мусор, т.к. не инициализирован.

ЗЫ:
Цитата(BrAgOl @  16.9.2011,  08:59 Найти цитируемый пост)
 if( d1 == d2 && COS1 == COS2 && COS1 == 0 ){

Никогда не сравнивайте плавающие типы на равенство. В крайнем случае (если без этого никак), подумайте об эпсилоне...

PM MAIL   Вверх
BrAgOl
Дата 16.9.2011, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 6.3.2005
Где: М.О.

Репутация: нет
Всего: нет



Цитата

Это еще повезло, здесь косинус может быть равен вообще чему угодно

А это еще почему, по теореме косинусов он должен получиться совершенно определенный косинус, другое дело погрешность вычислений...


Про d1 спасибо не углядел, конечно же d_1, погрешность снизилась до 0,0294

Цитата

Никогда не сравнивайте плавающие типы на равенство. В крайнем случае (если без этого никак), подумайте об эпсилоне...


А можно тут по подробней? 

Это сообщение отредактировал(а) BrAgOl - 16.9.2011, 10:31
PM MAIL   Вверх
volatile
Дата 16.9.2011, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(BrAgOl @  16.9.2011,  10:30 Найти цитируемый пост)
А это еще почему, по теореме косинусов

Причем здесь теорема косинусов? 
1. У вас неинициализированы данные
2. Вы запутались в координатах. Не думаю что кто-то захочет распутывать эту кашу.

Зачем вообще столько мемберов в классе?
PM MAIL   Вверх
BrAgOl
Дата 16.9.2011, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 6.3.2005
Где: М.О.

Репутация: нет
Всего: нет



Цитата(volatile @ 16.9.2011,  11:18)
Цитата(BrAgOl @  16.9.2011,  10:30 Найти цитируемый пост)
А это еще почему, по теореме косинусов

Причем здесь теорема косинусов? 
1. У вас неинициализированы данные
2. Вы запутались в координатах. Не думаю что кто-то захочет распутывать эту кашу.

Зачем вообще столько мемберов в классе?

я все уже распутал и исправил недочеты.
да и с координатами вроде все правильно.

а погрешность есть небольшая.
Я про эпсилон не совсем понял, не могли бы пояснить?
выход привести все к типу int и все после запятой в значении косинуса отбросится и  все будет работать, но это какой-то не красивый способ
PM MAIL   Вверх
volatile
Дата 16.9.2011, 23:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(BrAgOl @  16.9.2011,  14:02 Найти цитируемый пост)
я все уже распутал и исправил недочеты.

Цитата(BrAgOl @  16.9.2011,  10:30 Найти цитируемый пост)
погрешность снизилась до 0,0294

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


Цитата(BrAgOl @  16.9.2011,  14:02 Найти цитируемый пост)
Я про эпсилон не совсем понял, не могли бы пояснить?

вместо if (a==b) ...
нужно:
if (fabs(a-b) < epsilon) ...

где epsilon является довольно маленькой величиной, скажем .000001

PM MAIL   Вверх
BrAgOl
Дата 19.9.2011, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 6.3.2005
Где: М.О.

Репутация: нет
Всего: нет



Цитата(volatile @  16.9.2011,  23:46 Найти цитируемый пост)
вместо if (a==b) ...
нужно:
if (fabs(a-b) < epsilon) ...

где epsilon является довольно маленькой величиной, скажем .000001


при таком сравнении в моем случае все работает, а по идее не должно, так как косинус равен 0,0294118, а fabs(cos1 - cos2) получается 0, что естественно меньше эпсилона

Код

void Rect::setDecRect( double x_1, double y_1, double x_2, double y_2, double x_3, double y_3, double x_4, double y_4 )
{
    double d_1, d_2, l, w, COSlw, l1,w1, COSl1w1;
    if( x_1 <= 0 || x_2 <= 0 || y_1 <= 0 || y_2 <= 0 || x_3 <= 0 || x_4 <= 0 || y_3 <= 0 || y_4 <= 0 )
    {
        cout << "\nERROR! THE ENTERED POINTS ARE NEGATIVE. ENTER NEW DATA.\n";
        exit(1);
    }
    else
    {
        x1 = x_1;
        y1 = y_1;

        x2 = x_2;
        y2 = y_2;

        x3 = x_3;
        y3 = y_3;

        x4 = x_4;
        y4 = y_4;

        d_1 = sqrt( pow( ( x4 - x2 ), 2 ) + pow( ( y4 - y2 ), 2 ) );
        d_2 = sqrt( pow( ( x3 - x1 ), 2 ) + pow( ( y3 - y1 ), 2 ) );
        l = sqrt( pow( ( y2 - y1 ), 2 ) + pow( ( x2 - x1 ), 2 ) );
        w = sqrt( pow( ( y4 - y1 ), 2 ) + pow( ( x4 - x1 ), 2 ) );
        COSlw = ( ( l*l + w*w - d_1*d_1 ) / ( 2 * l*l*w*w) );
        l1 = sqrt( pow( ( y4 - y3 ), 2 ) + pow( ( x4 - x3 ), 2 ) );
        w1 = sqrt( pow( ( y3 - y2 ), 2 ) + pow( ( x3 - x2 ), 2 ) );
        COSl1w1 = ( ( l1*l1 + w1*w1 - d_1*d_1 ) / ( 2 * l1*l1*w1*w1) );


        COS1 = COSlw;
        COS2 = COSl1w1;
        d1 = d_1;
        d2 = d_2;

    }
    if( ( fabs( d1 - d2 ) < epsilon ) && ( fabs( COS1 - COS2 ) < epsilon )  )
    {
        length = l;
        width = w;
        cout << "COS1 = " << COS1 << " COS2 = " << COS2
        << " D1 = " << d1 << " D2 = " << d2 << "\n\n\n" << " fabs( d1 - d2 ) = " << fabs( d1 - d2 ) << " fabs( COS1 - COS2 ) = "
        << fabs( COS1 - COS2 ) << "\n\n\n";
    }
    else
    {
        cout << "\n\n\nERROR! THE ENTERED POINTS ARE ILLEGAL. ENTER NEW DATA.\n" << "COS1 = " << COS1 << " COS2 = " << COS2
        << " D1 = " << d1 << " D2 = " << d2 << "\n\n\n";
        exit(1);
    }
}


PM MAIL   Вверх
bsa
Дата 19.9.2011, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



BrAgOl, мне интересно, почему при вычислении COSl1w1 и COSlw у тебя используется в обоих случаях d_1*d_1? И вообще, зачем ты вычитаешь квадрат диагонали?

И вообще, кто тебя учил давать имена переменным? Еще в школе учат адекватным именам: прямоугольник ABCD, прямая AB, угол/треугольник BCD... В итоге бы у тебя получилось:
Код
BD = sqrt(pow(Bx*Bx - Dx*Dx, 2) + pow(By*By - Dy*Dy, 2));
AC = sqrt(pow(Ax*Ax - Cx*Cx, 2) + pow(Ay*Ay - Cy*Cy, 2));
if (fabs(AC - BD) >= epsilon) {
    std::cerr << "Error: it is not a rectangle" << std::endl;
    exit(1);
}
AB = sqrt(pow(Ax*Ax - Bx*Bx, 2) + pow(Ay*Ay - By*By, 2));
DA = sqrt(pow(Ax*Ax - Dx*Dx, 2) + pow(Ay*Ay - Dy*Dy, 2));
BC = sqrt(pow(Bx*Bx - Cx*Cx, 2) + pow(By*By - Cy*Cy, 2));
CD = sqrt(pow(Cx*Cx - Dx*Dx, 2) + pow(Cy*Cy - Dy*Dy, 2));
if ((fabs(AB - CD) >= epsilon) || (fabs(DA - BC) >= epsilon)) {
    std::cerr << "Error: is is not a rectangle" << std::endl;
    exit(1);
}
P = 2 * (AB + DA);
S = AB*DA;
std::cout << "Rectangle square: " << S << "\nRectangle perimeter: " << P << std::endl;

PM   Вверх
BrAgOl
Дата 19.9.2011, 15:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 6.3.2005
Где: М.О.

Репутация: нет
Всего: нет



Цитата(bsa @  19.9.2011,  14:57 Найти цитируемый пост)
BrAgOl, мне интересно, почему при вычислении COSl1w1 и COSlw у тебя используется в обоих случаях d_1*d_1? И вообще, зачем ты вычитаешь квадрат диагонали?



Потому что у противоположных углов моего прямоугольника общая диагональ, которая называется d_1 и считаю достатоным предполагать, что если 2 противоположных угла 90 градусов, то и остальные 90
а в квадрат возвожу, потому что ищу угол по теореме косинусов



А называл так, как нарисовал себе, если рисунок приложить все ясно станет.
PM MAIL   Вверх
bsa
Дата 19.9.2011, 16:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Цитата(BrAgOl @  19.9.2011,  15:21 Найти цитируемый пост)
если 2 противоположных угла 90 градусов, то и остальные 90

ты не сравниваешь с 90 градусов. А сравниваешь лишь косинусы противоположных углов судя по названию переменных. А вот способ их вычисления меня несколько удивляет...

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

Это сообщение отредактировал(а) bsa - 19.9.2011, 16:14
PM   Вверх
BrAgOl
Дата 19.9.2011, 16:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 6.3.2005
Где: М.О.

Репутация: нет
Всего: нет



Цитата(bsa @  19.9.2011,  16:12 Найти цитируемый пост)
ты не сравниваешь с 90 градусов. А сравниваешь лишь косинусы противоположных углов судя по названию переменных. А вот способ их вычисления меня несколько удивляет...

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

в строке:
Код

if( d1 == d2 && COS1 == COS2 && COS1 == 0 )

помимо сравнения на равенство диагоналей и косинусов, также проверяется и угол в 90 градусов, а именно в последнем сравнении, т.к. косинус 90 градусов это 0

А чем так способ удивляет? Может конечно я плохо помню школьную программу, но другого способа и не придумал как в треугольнике по всем известным сторонам углы найти

кстати имена у меня не случайные все крутится вокруг координат х, у и переменных length и width (l, w)  ну и косинус между (l, w) это один угол, а косинус между (l1, w1), это противоположный, как-то так... Не спорю ваш вариант интуитивно понятней, но тут дело вкуса

Это сообщение отредактировал(а) BrAgOl - 19.9.2011, 16:54
PM MAIL   Вверх
volatile
Дата 19.9.2011, 18:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



BrAgOl, я уже говорил вам
Цитата(volatile @  16.9.2011,  11:18 Найти цитируемый пост)
Вы запутались в координатах

Хотел чтобы сами разобрались, но увы...

Цитата(BrAgOl @  16.9.2011,  08:59 Найти цитируемый пост)
  Rect RR( 2, 4, 2, 7, 7, 4, 7, 7 );

Здесь их надо просто переставить вот так:
Цитата(BrAgOl @  16.9.2011,  08:59 Найти цитируемый пост)
  Rect RR( 2, 4, 2, 7, 7, 7, 7, 4 );


Удачи! smile 

PM MAIL   Вверх
BrAgOl
Дата 20.9.2011, 09:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 6.3.2005
Где: М.О.

Репутация: нет
Всего: нет



 smile  Спасибо за подсказку не обратил внимание, значения косинуса получились -7,03912е-018, что в принципе стремится к нулю.

А по точкам, наверное было бы полезно организовать проверку введенных пар точек, и при хаотичном введении пар, произвести обмен для упорядочивания...
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

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


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0611 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.