特定的直角三角形在 Cpp

问题描述

我们的 OOP 老师给了我一个作业。尽管我的代码看起来不错,但我正面临这个问题。

我必须从用户那里获取三角形顶点的坐标,并且必须判断它是否是一个直角三角形。所以我简单地用毕达哥拉斯定理来找出它,众所周知使用条件:h * h = b * b + p * p

但令人惊讶的是,这不适用于某些特定的直角三角形。 这是一个这样的三角形:

顶点 A:(x,y) = (1,3)

顶点 B:(x,1)

顶点 C:(x,y) = (5,1)

计算完美,我通过打印计算得出了这一点,但仍然不起作用

然后我尝试以这种方式使用 sqrt() 库中的 cmath 函数: h = sqrt(b * b + p * p)

逻辑上是一样的,但确实有效。

我想了解一下,为什么之前的方法不起作用?

这是我的代码的简化版本:

#include <iostream>
#include <cmath>

using namespace std;

class Vertex {

    double x,y;

public:
    void take_input(char obj) {
        cout << endl << "   Taking Coordinates of Vertex " << obj << ": " << endl;

        cout << "       Enter the x component: ";
        cin >> x;
        cout << "       Enter the y component: ";
        cin >> y;
    }

    double distance(Vertex p) {
        double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));

        return dist;
    }
};

class Triangle {
    Vertex a,b,c;

public:

    void take_inp(string obj) {
        cout << endl << "Taking Vertices of the Triangle " << obj << ": " << endl;
        cout << "   Verteces should be in a counter clockwise order (as per convention)." << endl;

        a.take_input('A');
        b.take_input('B');
        c.take_input('C');
    }

    void is_rt_ang() {

        double h = a.distance(c)*a.distance(c);
        double bp = a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c);

        /*
            // Strangely this attempt works which is logically the same: 
            double h = a.distance(c);
            double bp = sqrt(a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c));
        */

        if (h == bp) {
            cout << "Angle is 90" << endl;
            cout << h << " = " << bp << endl;
            cout << "It is Right-Angled" << endl;
        }
        else {
            cout << "Angle is not 90!" << endl;
            cout << h << " != " << bp << endl;
            cout << "It is Not a Right-Angled" << endl;
        }
    }
};

int main()
{
    Triangle tri1,tri2;

    tri1.take_inp("tri1");

    tri1.is_rt_ang();

    return 0;
}

解决方法

线

double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));

Vertex::distance 方法中为您提供平方根的近似值,该近似值很少与精确答案重合。这是因为大多数实数不能用浮点运算表示。

但是在给定的代码示例中,您可以不使用 sqrt。用方法替换 Vertex::distance 方法

 double distance_square(Vertex p) {
    double dist_square = (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y);
    return dist_square;
}

并在 Triangle::is_rt_ang 中这样称呼它:

    double h = a.distance_square(c);
    double bp = a.distance_square(b) + b.distance_square(c);

这个解决方案仍然有缺陷,因为浮点乘法也容易出现舍入错误。但是,如果保证您将只使用整数坐标,您可以用整数替换代码中的所有双精度数,并且对于它们,乘法没有问题(除了可能超出大数的界限)。

编辑:还有关于打印的评论

它计算得很好,我通过打印 计算,但仍然不起作用。

当您打印双打时,您需要手动设置精度以避免四舍五入。如果在你的代码中我替换了一行

cout << h << " != " << bp << endl;

cout << std::setprecision(std::numeric_limits<double>::digits10) << std::fixed << h << " != " << bp << endl;

然后例如我得到输出的问题的三角形

角度不是90!
20.000000000000004 != 20.000000000000000
不是直角

为了编译,您需要添加 #include <limits>#include <iomanip>

,

在您的 is_rt_ang 函数中,您假设您的斜边始终是边 AC,但您似乎没有采取任何措施来验证这一点。

double h = a.distance(c)*a.distance(c);
double bp = a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c);

您可以先尝试获取所有距离的平方,(AC)^2(AB)^2(BC)^2,然后通过从三个中取出最大值来找到斜边的候选者,然后执行以下操作:

bool isRightTriangle = max == (min1 + min2)

您可能还会遇到浮点数的某种舍入错误。由于固有的舍入误差,在比较浮点数时通常使用 epsilon 值。如果您不需要浮点值,可以使用整数,或者如果您确实需要浮点值,请尝试在等式中使用 epsilon 值,例如:

abs(h - bp) <= epsilon

您应该能够在网络上找到有关浮点值、舍入误差和机器 epsilon 的更多信息。

这是一个 SO Q/A 的链接,其中讨论了可能对您来说是一个很好的资源的浮点数学:Is floating point math broken?

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...