簡體   English   中英

CGAL惰性數的大區間上限

[英]Large interval upper bound of a CGAL lazy number

我有一個s = a_1/b_1 + a_2/b_2 +...形式的總和示例,其中a_ib_i是 CGAL 惰性數字,因此s.interval()返回的間隔非常大。 它的下限接近預期值(並且接近CGAL::as_double(s) )但它的上限很大(甚至無限大)。

但是,如果我使用mydivision(a_i, b_i) (定義如下)而不是a_i/b_i ,則間隔會像預期的那樣變窄。 這是我的mydivision

typedef CGAL::Quotient<CGAL::MP_Float> Quotient;
typedef CGAL::Lazy_exact_nt<Quotient>  lazyScalar;

lazyScalar mydivision(lazyScalar x1, lazyScalar x2) {
  Quotient q1 = x1.exact();
  Quotient q2 = x2.exact();
  lazyScalar q = lazyScalar(Quotient(
    q1.numerator() * q2.denominator(), q1.denominator() * q2.numerator())
  );
  return q;
}

這是總和(它轉到pi/2 - 1 ):

在此處輸入圖像描述

這是完整的代碼:

#include <vector>
#include <CGAL/number_utils.h>
#include <CGAL/Lazy_exact_nt.h>
#include <CGAL/MP_Float.h>
#include <CGAL/Quotient.h>
#include <CGAL/Interval_nt.h>

typedef CGAL::Quotient<CGAL::MP_Float> Quotient;
typedef CGAL::Lazy_exact_nt<Quotient>  lazyScalar;
typedef std::vector<lazyScalar>        lazyVector;

// "my" division
lazyScalar mydivision(lazyScalar x1, lazyScalar x2) {
  Quotient q1 = x1.exact();
  Quotient q2 = x2.exact();
  lazyScalar q = lazyScalar(Quotient(
    q1.numerator() * q2.denominator(), q1.denominator() * q2.numerator())
  );
  return q;
}

// sum the elements of a vector of lazy numbers
lazyScalar lazySum(lazyVector lv) {
  const size_t n = lv.size();
  lazyScalar sum(0);
  for(size_t i = 0; i < n; i++) {
    sum += lv[i];
  }
  return sum;
}

// element-wise division of two vectors of lazy numbers
lazyVector lv1_dividedby_lv2(lazyVector lv1, lazyVector lv2) {
  const size_t n = lv1.size();
  lazyVector lv(n);
  for(size_t i = 0; i < n; i++) {
    lv[i] = lv1[i] / lv2[i];
  }
  return lv;
}

// same as above using "my" division
lazyVector lv1_mydividedby_lv2(lazyVector lv1, lazyVector lv2) {
  const size_t n = lv1.size();
  lazyVector lv(n);
  for(size_t i = 0; i < n; i++) {
    lv[i] = mydivision(lv1[i], lv2[i]);
  }
  return lv;
}

// cumulative products of the elements of a vector of lazy numbers
lazyVector lazyCumprod(lazyVector lvin) {
  const size_t n = lvin.size();
  lazyVector lv(n);
  lazyScalar prod(1);
  for(size_t i = 0; i < n; i++) {
    prod *= lvin[i];
    lv[i] = prod;
  }
  return lv;
}

// the series with the ordinary division
lazyScalar Euler(int n) {
  lazyVector lv1(n);
  for(int i = 0; i < n; i++) {
    lv1[i] = lazyScalar(i + 1);
  }
  lazyVector lv2(n);
  for(int i = 0; i < n; i++) {
    lv2[i] = lazyScalar(2*i + 3);
  }
  return lazySum(lv1_dividedby_lv2(lazyCumprod(lv1), lazyCumprod(lv2))); 
}

// the series with "my" division
lazyScalar myEuler(int n) {
  lazyVector lv1(n);
  for(int i = 0; i < n; i++) {
    lv1[i] = lazyScalar(i + 1);
  }
  lazyVector lv2(n);
  for(int i = 0; i < n; i++) {
    lv2[i] = lazyScalar(2*i + 3);
  }
  return lazySum(lv1_mydividedby_lv2(lazyCumprod(lv1), lazyCumprod(lv2))); 
}

// test - the difference starts to occur for n=170
int main() {
  lazyScalar euler = Euler(171);
  CGAL::Interval_nt<false> interval = euler.approx();
  std::cout << "lower bound: " << interval.inf() << "\n"; // prints 0.57
  std::cout << "upper bound: " << interval.sup() << "\n"; // prints inf
  lazyScalar myeuler = myEuler(171);
  CGAL::Interval_nt<false> myinterval = myeuler.approx();
  std::cout << "lower bound: " << myinterval.inf() << "\n"; // prints 0.57
  std::cout << "upper bound: " << myinterval.sup() << "\n"; // prints 0.57
  return 0;
}

為什么這個上限很大?

您正在計算階乘和類似產品。 一旦它們超過了double的最大值,一對 double 可以做的表示的間隔就不多了。

至少它給了你一個安全的答案,你仍然可以在最后使用exact()得到真正的答案。 你的部門會更簡單return exact(x1/x2); ,但您甚至不需要經常調用exact ,只需exact(Euler(171))

將值計算為(1/3)*(2/5)*(3/7)而不是(1*2*3)/(3*5*7)可以避免這么快發生溢出。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM