[英]Large interval upper bound of a CGAL lazy number
我有一個s = a_1/b_1 + a_2/b_2 +...
形式的總和示例,其中a_i
和b_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.