C++ 精确数性能

C++ 精确数性能,c++,computational-geometry,cgal,C++,Computational Geometry,Cgal,我用CGAL进行几何计算。我的计算需要精确的算术运算(即加法、减法、乘法、除法)。因此,到目前为止,我的最佳解决方案是以下数字类型: #include <CGAL/Exact_predicates_exact_constructions_kernel.h> typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Lazy_exact_nt<CGAL::Quotient<

我用CGAL进行几何计算。我的计算需要精确的算术运算(即加法、减法、乘法、除法)。因此,到目前为止,我的最佳解决方案是以下数字类型:

#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef CGAL::Lazy_exact_nt<CGAL::Quotient<CGAL::MP_Float> > NT;
现在我有点担心与“标准”浮点算法相比,精确算法的性能开销。与double相比,CGAL的精确数字类型的性能差多少?是否存在一个上限,说明性能开销最大可能有多大

编辑我应该多描述一下我需要实现的目标。我想在3D空间中实现三角形/三角形分割。如果两个三角形相交,我想在它们的交线上分开它们。 当我有非常小的三角形或者两个三角形的交集非常小时,就会出现问题。这会导致舍入错误和我的程序崩溃。我曾尝试使用公差值进行管理,但这只在99%的时间内有效。我想写一个100%工作时间的软件,所以我真的需要精确的计算。 实际上我只需要两件事:

  • 三维矢量的精确表示
  • 精确谓词(关于,==操作)
  • 计算两个三角形相交线的精确算法
关于交叉线计算,我有如下计算:

public Vector3m ComputeLineIntersection(IntersectionLine& otherLine)
    {
        //x = x1 + a1*t = x2 + b1*s
        //y = y1 + a2*t = y2 + b2*s
        //z = z1 + a3*t = z2 + b3*s

        Vector3m linePoint = otherLine._point;
        Vector3m lineDirection = otherLine._direction;

        NT t;
        if ((_direction.Y * lineDirection.X - _direction.X * lineDirection.Y) != 0)
        {
            t = (-_point.Y * lineDirection.X + linePoint.Y * lineDirection.X + lineDirection.Y * _point.X - lineDirection.Y * linePoint.X) / (_direction.Y * lineDirection.X - _direction.X * lineDirection.Y);
        }
        else if ((-_direction.X * lineDirection.Z + _direction.Z * lineDirection.X) != 0)
        {
            t = -(-lineDirection.Z * _point.X + lineDirection.Z * linePoint.X + lineDirection.X * _point.Z - lineDirection.X * linePoint.Z) / (-_direction.X * lineDirection.Z + _direction.Z * lineDirection.X);
        }
        else if ((-_direction.Z*lineDirection.Y + _direction.Y*lineDirection.Z) != 0)
        {
            t = (_point.Z*lineDirection.Y - linePoint.Z*lineDirection.Y - lineDirection.Z*_point.Y +
                 lineDirection.Z*linePoint.Y)/(-_direction.Z*lineDirection.Y + _direction.Y*lineDirection.Z);
        }
        else
        {
            throw new Exception("Intersection line not correctly calculated.");
        }

        NT x = _point.X + _direction.X * t;
        NT y = _point.Y + _direction.Y* t;
        NT z = _point.Z + _direction.Z * t;

        return new Vector3m(x, y, z);
    }

为什么不
typedef内核::FT-NT?开销将相当大。没有上限,
double
的大小是恒定的,而经过多次运算后的有理数大小可以任意增长。在实践中,我们期望区间运算对于大多数运算来说是足够的,并且开销是一个常数。对不起,我不是数学家。我已经研究过CGAL的字段数类型和区间算法,但我仍然不确定现在应该使用什么。你的意思是我应该使用
typedef内核::FT-NT。当我使用这种类型时,计算准确吗?开销是恒定的吗?我所说的
Kernel::FT
的意思是,编写为
NT
编写的复杂类型没有意义,内核已经执行了一个合适的typedef(可能与您的类型相同,具体取决于GMP的可用性)。是的,计算是精确的。在级联构造时,没有任何数字类型可以保证在恒定时间内精确计算。然而,如果你所有的三角形都来自双坐标,并且你只与它们相交,那么在某种意义上,构造的“深度”是低的,开销是恒定的。我明白了。我已经使用rational数据类型实现了我的三角剖分算法,并且没有CGAL。计算是稳健的,但本质上是缓慢的。所以我希望CGAL能加快我的计算速度。因此,归根结底,CGAL并没有带来性能改进,对吗?实际上是这样的。惰性类型使用区间算法,只要这是足够的,并且只在少数情况下进行缓慢的精确有理计算。你为什么不试试看性能是否适合你呢?为什么不
typedef内核::FT-NT?开销将相当大。没有上限,
double
的大小是恒定的,而经过多次运算后的有理数大小可以任意增长。在实践中,我们期望区间运算对于大多数运算来说是足够的,并且开销是一个常数。对不起,我不是数学家。我已经研究过CGAL的字段数类型和区间算法,但我仍然不确定现在应该使用什么。你的意思是我应该使用
typedef内核::FT-NT。当我使用这种类型时,计算准确吗?开销是恒定的吗?我所说的
Kernel::FT
的意思是,编写为
NT
编写的复杂类型没有意义,内核已经执行了一个合适的typedef(可能与您的类型相同,具体取决于GMP的可用性)。是的,计算是精确的。在级联构造时,没有任何数字类型可以保证在恒定时间内精确计算。然而,如果你所有的三角形都来自双坐标,并且你只与它们相交,那么在某种意义上,构造的“深度”是低的,开销是恒定的。我明白了。我已经使用rational数据类型实现了我的三角剖分算法,并且没有CGAL。计算是稳健的,但本质上是缓慢的。所以我希望CGAL能加快我的计算速度。因此,归根结底,CGAL并没有带来性能改进,对吗?实际上是这样的。惰性类型使用区间算法,只要这是足够的,并且只在少数情况下进行缓慢的精确有理计算。你为什么不试一下,看看性能是否适合你?
public Vector3m ComputeLineIntersection(IntersectionLine& otherLine)
    {
        //x = x1 + a1*t = x2 + b1*s
        //y = y1 + a2*t = y2 + b2*s
        //z = z1 + a3*t = z2 + b3*s

        Vector3m linePoint = otherLine._point;
        Vector3m lineDirection = otherLine._direction;

        NT t;
        if ((_direction.Y * lineDirection.X - _direction.X * lineDirection.Y) != 0)
        {
            t = (-_point.Y * lineDirection.X + linePoint.Y * lineDirection.X + lineDirection.Y * _point.X - lineDirection.Y * linePoint.X) / (_direction.Y * lineDirection.X - _direction.X * lineDirection.Y);
        }
        else if ((-_direction.X * lineDirection.Z + _direction.Z * lineDirection.X) != 0)
        {
            t = -(-lineDirection.Z * _point.X + lineDirection.Z * linePoint.X + lineDirection.X * _point.Z - lineDirection.X * linePoint.Z) / (-_direction.X * lineDirection.Z + _direction.Z * lineDirection.X);
        }
        else if ((-_direction.Z*lineDirection.Y + _direction.Y*lineDirection.Z) != 0)
        {
            t = (_point.Z*lineDirection.Y - linePoint.Z*lineDirection.Y - lineDirection.Z*_point.Y +
                 lineDirection.Z*linePoint.Y)/(-_direction.Z*lineDirection.Y + _direction.Y*lineDirection.Z);
        }
        else
        {
            throw new Exception("Intersection line not correctly calculated.");
        }

        NT x = _point.X + _direction.X * t;
        NT y = _point.Y + _direction.Y* t;
        NT z = _point.Z + _direction.Z * t;

        return new Vector3m(x, y, z);
    }