25 #include "absl/base/casts.h"
26 #include "absl/base/internal/endian.h"
35 void ReorderAndCapTerms(
double*
min,
double*
max) {
37 if (*
min > 0.0) *
min = 0.0;
38 if (*
max < 0.0) *
max = 0.0;
41 template <
bool use_bounds>
43 const std::vector<double>& lb,
44 const std::vector<double>& ub,
double scaling_factor,
46 double* max_scaled_sum_error) {
47 double max_error = 0.0;
48 double min_error = 0.0;
50 const int size =
input.size();
51 for (
int i = 0; i < size; ++i) {
52 const double x =
input[i];
53 if (x == 0.0)
continue;
54 const double scaled = x * scaling_factor;
63 const double error = std::round(scaled) - scaled;
64 const double error_lb = (use_bounds ? error * lb[i] : -error);
65 const double error_ub = (use_bounds ? error * ub[i] : error);
66 max_error +=
std::max(error_lb, error_ub);
67 min_error +=
std::min(error_lb, error_ub);
69 *max_scaled_sum_error =
std::max(std::abs(max_error), std::abs(min_error));
72 template <
bool use_bounds>
74 const std::vector<double>& lb,
75 const std::vector<double>& ub,
76 int64_t max_absolute_sum,
77 double* scaling_factor) {
78 const double kInfinity = std::numeric_limits<double>::infinity();
84 if (max_absolute_sum < 0)
return;
92 int factor_exponent = 0;
95 bool recompute_sum =
false;
96 bool is_first_value =
true;
98 const int size =
input.size();
99 for (
int i = 0; i < size; ++i) {
100 const double x =
input[i];
101 double min_term = use_bounds ? x * lb[i] : -x;
102 double max_term = use_bounds ? x * ub[i] : x;
103 ReorderAndCapTerms(&min_term, &max_term);
110 if (min_term == 0.0 && max_term == 0.0)
continue;
114 const double c =
std::max(-min_term, max_term);
115 int candidate = msb - ilogb(c);
116 if (std::round(ldexp(std::abs(c), candidate)) > max_absolute_sum) {
119 DCHECK_LE(std::abs(
static_cast<int64_t
>(round(ldexp(c, candidate)))),
123 if (is_first_value || candidate < factor_exponent) {
124 is_first_value =
false;
125 factor_exponent = candidate;
126 recompute_sum =
true;
130 static_cast<int64_t
>(std::round(ldexp(min_term, factor_exponent)));
132 static_cast<int64_t
>(std::round(ldexp(max_term, factor_exponent)));
133 if (sum_min >
static_cast<uint64_t
>(max_absolute_sum) ||
134 sum_max >
static_cast<uint64_t
>(max_absolute_sum)) {
136 recompute_sum =
true;
146 while (recompute_sum) {
149 for (
int j = 0; j <= i; ++j) {
150 const double x =
input[j];
151 double min_term = use_bounds ? x * lb[j] : -x;
152 double max_term = use_bounds ? x * ub[j] : x;
153 ReorderAndCapTerms(&min_term, &max_term);
155 static_cast<int64_t
>(std::round(ldexp(min_term, factor_exponent)));
157 static_cast<int64_t
>(std::round(ldexp(max_term, factor_exponent)));
159 if (sum_min >
static_cast<uint64_t
>(max_absolute_sum) ||
160 sum_max >
static_cast<uint64_t
>(max_absolute_sum)) {
163 recompute_sum =
false;
167 *scaling_factor = ldexp(1.0, factor_exponent);
173 const std::vector<double>& lb,
174 const std::vector<double>& ub,
double scaling_factor,
176 double* max_scaled_sum_error) {
177 ComputeScalingErrors<true>(
input, lb, ub, scaling_factor,
182 const std::vector<double>& lb,
183 const std::vector<double>& ub,
184 int64_t max_absolute_sum) {
185 double scaling_factor;
186 GetBestScalingOfDoublesToInt64<true>(
input, lb, ub, max_absolute_sum,
188 return scaling_factor;
192 int64_t max_absolute_sum,
193 double* scaling_factor,
195 double max_scaled_sum_error;
196 GetBestScalingOfDoublesToInt64<false>(
input, {}, {}, max_absolute_sum,
198 ComputeScalingErrors<false>(
input, {}, {}, *scaling_factor,
203 double scaling_factor) {
205 const int size =
static_cast<int>(x.size());
206 for (
int i = 0; i < size && gcd != 1; ++i) {
207 int64_t
value = std::abs(std::round(x[i] * scaling_factor));
209 if (
value == 0)
continue;
216 const int64_t r = gcd %
value;
222 return gcd > 0 ? gcd : 1;
226 static_assert(CHAR_BIT == 8);
227 static_assert(
sizeof(
double) == 8);
229 const uint64_t bit_rep =
230 absl::little_endian::FromHost64(absl::bit_cast<uint64_t>(
value));
231 return static_cast<int>((bit_rep >> 52) & 0x7FF) - 1023;
235 mutable_value =
fast_scalbn(mutable_value, exponent);
239 if (
value == 0.0)
return 0.0;
241 absl::little_endian::FromHost64(absl::bit_cast<uint64_t>(
value));
243 constexpr uint64_t kExponentMask(0x7FF0000000000000);
247 const uint64_t value_exponent =
248 (bit_rep + (
static_cast<uint64_t
>(exponent) << 52)) & kExponentMask;
249 bit_rep &= ~kExponentMask;
250 bit_rep |= value_exponent;
251 return absl::bit_cast<double>(absl::little_endian::ToHost64(bit_rep));
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Collection of objects used to extend the Constraint Solver library.
int fast_ilogb(double value)
void ComputeScalingErrors(const std::vector< double > &input, const std::vector< double > &lb, const std::vector< double > &ub, double scaling_factor, double *max_relative_coeff_error, double *max_scaled_sum_error)
double fast_scalbn(double value, int exponent)
void fast_scalbn_inplace(double &mutable_value, int exponent)
int64_t ComputeGcdOfRoundedDoubles(const std::vector< double > &x, double scaling_factor)
double GetBestScalingOfDoublesToInt64(const std::vector< double > &input, const std::vector< double > &lb, const std::vector< double > &ub, int64_t max_absolute_sum)
int MostSignificantBitPosition64(uint64_t n)
static int input(yyscan_t yyscanner)
double max_relative_coeff_error
constexpr double kInfinity