CGAL:点上线?

时间:2014-05-29 16:27:02

标签: precision cgal

我在CGAL遇到了一件奇怪的事情。我有一条线和一条点应该在这条线上。这段代码

typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;

int main( ) {
  CGAL::Line_2<Kernel> l(0.2, 1.0, -1.4);

  std::cout << l.has_on(CGAL::Point_2<Kernel>(-3.0, 2.0)) << std::endl;
  std::cout << l.y_at_x(-3.0).exact() << std::endl;

  return 0;
}

产生输出:

0
36028797018963967/18014398509481984

好吧,也许Exact_predicates_exact_constructions_kernel不够好......(为什么?)

我尝试使用CGAL::Quotient定义的内核代替:

typedef CGAL::Quotient<CGAL::MP_Float> NT;
typedef CGAL::Cartesian<NT> Kernel;

int main( ) {
  CGAL::Line_2<Kernel> l(0.2, 1.0, -1.4);

  std::cout << l.has_on(CGAL::Point_2<Kernel>(-3.0, 2.0)) << std::endl;
  std::cout << l.y_at_x(-3.0) << std::endl;

  return 0;
}

结果对我来说更加神秘:

0
2/1

我错过了什么或者它是一个错误吗?

1 个答案:

答案 0 :(得分:3)

从0.2构造直线时,会发生两次转换。编译器将字符串“0.2”转换为double。然后,这个double被转换为内核的数字类型(在这种情况下是完全合理的)。

问题是0.2到double的转换并不准确,因为0.2是浮点值无法表示的有理数,因此引入了一些不精确性。 CGAL对此无能为力。

如果你需要完全代表0.2,你需要使用类似的东西:

  CGAL::Line_2<Kernel> l(NT(2)/NT(10), 1.0, NT(-14)/NT(10));

或者,以十的幂为单位缩放问题,以便所有坐标都变为整数。

某些有理数类型也有可能直接从表示有理数的字符串构造而没有任何舍入,但我认为CGAL::Quotient<MP_Float>不能。