关于代数数的计算

时间:2014-01-03 01:54:24

标签: c++ cgal leda rs algebraic-number

我想对常规多边形进行精确计算。为此,我编写了您在下面找到的代码。但表达式cos*cos将无法编译。显然,我所使用的代数数字类型没有定义乘法。我想我将不得不尝试其他方法。目前似乎有两个候选人:

  1. RS显然提供了一些更高级的代数功能,CGAL has support for it。但我在相关的标题中看不到乘法运算符,所以我怀疑它会按照我想要的方式进行乘法运算。
  2. leda::real似乎是代数实数的一种类型。我可能不得不重写我的代码,但应该可以实现类似的结果。也许我甚至可以将我在CGAL中计算的cos转换为这样的leda::real。 LEDA标头至少看起来有operator*。 LEDA可供我免费使用,但仍然是封闭源。 CGAL 4.3的leda_real.h看起来很奇怪:它指的是leda_real而不是leda::real,所以它可能是为过时版本的LEDA而写的。它显然包含了自己,看起来毫无意义。
  3. 这些替代方案中哪一种最适合构建精确的CGAL内核,能够描述任意 n 的常规 n ?这些都有用吗?我还缺少另一种选择吗?

    由于我的计算机上没有安装RS或LEDA,在开始构建之前我更喜欢受过教育的意见,甚至可能为我的Gentoo linux编写安装说明(“ebuilds”)。

    #include <string>
    #include <iostream>
    #include <sstream>
    #include <vector>
    
    //define CGAL_USE_RS
    #include <CGAL/Gmpz.h>
    #include <CGAL/Algebraic_kernel_d_1.h>
    #include <CGAL/Algebraic_kernel_rs_gmpz_d_1.h>
    #include <CGAL/Homogeneous.h>
    #include <CGAL/Arr_segment_traits_2.h>
    #include <CGAL/Arrangement_2.h>
    
    #define DBG(x) std::cerr << x << std::endl
    
    typedef CGAL::Gmpz ZZ;
    // typedef CGAL::Algebraic_kernel_rs_gmpz_d_1 AK;
    typedef CGAL::Algebraic_kernel_d_1<ZZ> AK;
    typedef AK::Polynomial_1 Polynomial;
    typedef AK::Algebraic_real_1 AA;
    typedef AK::Coefficient Coeff;
    typedef AK::Bound Bound;
    typedef AK::Multiplicity_type Multiplicity;
    typedef CGAL::Homogeneous<AK> Kernel;
    typedef CGAL::Arr_segment_traits_2<Kernel> Traits;
    typedef Kernel::Point_2 Point;
    typedef Kernel::Segment_2 Segment;
    typedef CGAL::Arrangement_2<Traits> Arrangement;
    
    static unsigned run(unsigned short n) {
      AK ak;
      AK::Construct_algebraic_real_1 to_AA = ak.construct_algebraic_real_1_object();
      AK::Solve_1 solve = ak.solve_1_object();
      Polynomial x{CGAL::shift(Polynomial(1), 1)}, twox{2*x};
      Polynomial a{1}, b{x};
      for (unsigned short i = 2; i <= n; ++i) {
        Polynomial c = twox*b - a;
        a = b;
        b = c;
      }
      std::vector<std::pair<AA, Multiplicity>> roots;
      solve(b - 1, std::back_inserter(roots));
      AA one{1}, cos{-2};
      for (auto i = roots.begin(), e = roots.end(); i != e; ++i) {
        AA cur = i->first;
        if (cur < one && cur > cos)
          cos = cur;
      }
      AA sin = CGAL::sqrt(to_AA(1) - cos*cos);
      //DBG("sin="<<CGAL::to_double(sin)<<", cos="<<CGAL::to_double(cos));
      return 0;
    }
    
    int main(int argc, char** argv) {
      for (int i = 1; i < argc; ++i) {
        unsigned short n;
        std::istringstream(argv[i]) >> n;
        std::cout << n << ": " << run(n) << std::endl;
      }
      return 0;
    }
    

1 个答案:

答案 0 :(得分:1)

CGAL还附带CORE library,它提供您需要的操作。

以下是一些代码(由OP自己提供)来准确计算sin和cos:

#include <utility>
#include <CGAL/CORE_Expr.h>
#include <CGAL/Polynomial.h>
#include <CGAL/number_utils.h>

typedef CORE::Expr AA;
typedef CGAL::Polynomial<AA> Polynomial;

// return sin(θ) and cos(θ) for θ = 2π/n
static std::pair<AA, AA> sin_cos(unsigned short n) {
  // We actually use -x instead of x since root_of will give the k-th
  // smallest root but we want the second largest one without counting.
  Polynomial x{CGAL::shift(Polynomial(-1), 1)}, twox{2*x};
  Polynomial a{1}, b{x};
  for (unsigned short i = 2; i <= n; ++i) {
    Polynomial c = twox*b - a;
    a = b;
    b = c;
  }
  a = b - 1;
  AA cos = -CGAL::root_of(2, a.begin(), a.end());
  AA sin = CGAL::sqrt(AA(1) - cos*cos);
  return std::make_pair(sin, cos);
}