Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
rational_approximation.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <cmath>
17#include <cstdlib>
18#include <limits>
19
21
22namespace operations_research {
23
24// Computes a rational approximation numerator/denominator for value x
25// using a continued fraction algorithm. The absolute difference between the
26// output fraction and the input "x" will not exceed "precision".
27Fraction RationalApproximation(const double x, const double precision) {
28 DCHECK_LT(x, std::numeric_limits<double>::infinity());
29 DCHECK_GT(x, -std::numeric_limits<double>::infinity());
30 // All computations are made on long doubles to guarantee the maximum
31 // precision for the approximations. This way, the approximations when
32 // Fractional is float or double are as accurate as possible.
33 long double abs_x = std::abs(x);
34 long double y = abs_x;
35 int64_t previous_numerator = 0;
36 int64_t previous_denominator = 1;
37 int64_t numerator = 1;
38 int64_t denominator = 0;
39 while (true) {
40 const int64_t term = static_cast<int64_t>(std::floor(y));
41 const int64_t new_numerator = term * numerator + previous_numerator;
42 const int64_t new_denominator = term * denominator + previous_denominator;
43 // If there was an overflow, we prefer returning a not-so-good approximation
44 // rather than something that is completely wrong.
45 if (new_numerator < 0 || new_denominator < 0) break;
46 previous_numerator = numerator;
47 previous_denominator = denominator;
48 numerator = new_numerator;
49 denominator = new_denominator;
50 long double numerator_approximation = abs_x * denominator;
51 if (std::abs(numerator_approximation - numerator) <=
52 precision * numerator_approximation) {
53 break;
54 }
55 y = 1 / (y - term);
56 }
57 return Fraction((x < 0) ? -numerator : numerator, denominator);
58}
59} // namespace operations_research
IntegerValue y
In SWIG mode, we don't want anything besides these top-level includes.
Fraction RationalApproximation(const double x, const double precision)
std::pair< int64_t, int64_t > Fraction
const Variable x
Definition qp_tests.cc:127