Вычисления на алгебраических числах
Я хотел бы сделать точные вычисления на правильных многоугольниках. Для этого я написал код, который вы найдете ниже. Но выражение cos*cos
не будет компилироваться. Очевидно, умножение не определено для используемого типа алгебраических чисел. Я думаю, мне придется попробовать другой подход. В настоящее время, кажется, есть два кандидата:
- Очевидно, что RS предоставляет более продвинутую алгебраическую функциональность, и CGAL поддерживает ее. Но я не вижу операторов умножения в связанных заголовках, поэтому я сомневаюсь, что он будет выполнять умножение так, как мне хотелось бы.
- Похоже, что leda::real является типом алгебраических действительных чисел. Возможно, мне придется переписать мой код, но должно быть возможно добиться аналогичных результатов. Возможно, я мог бы даже преобразовать
cos
Я вычислил в CGAL такойleda::real
, Заголовок LEDA, по крайней мере, имеетoperator*
, LEDA бесплатна для моего использования, но все еще закрытый источник. А такжеleda_real.h
для CGAL 4.3 выглядит странно: это относится кleda_real
неleda::real
Так что, возможно, это написано для устаревшей версии ЛЕДА. И это, по-видимому, включает в себя, что выглядит довольно бессмысленно.
Какая из этих альтернатив лучше всего подойдет для построения точного ядра CGAL, способного описывать регулярные n- углы для произвольных n? Работает ли вообще что-нибудь из этого? Есть ли другая альтернатива, которую я пропускаю?
Поскольку на моем компьютере не установлены ни RS, ни LEDA, я бы предпочел обоснованное мнение, прежде чем я начну их создавать, и, возможно, даже написание инструкций по установке ("ebuilds") для моего Gentoo linux.
#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 ответ
CGAL также поставляется с библиотекой CORE, которая обеспечивает необходимые вам операции.
Вот некоторый код (предоставленный самим ОП) для точного вычисления этого греха и 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);
}