25#include "absl/base/casts.h"
26#include "absl/base/internal/endian.h"
35void ReorderAndCapTerms(
double*
min,
double*
max) {
37 if (*
min > 0.0) *
min = 0.0;
38 if (*
max < 0.0) *
max = 0.0;
41template <
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));
72template <
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 > max_absolute_sum || sum_max > max_absolute_sum) {
135 recompute_sum =
true;
145 while (recompute_sum) {
148 for (
int j = 0; j <= i; ++j) {
149 const double x =
input[j];
150 double min_term = use_bounds ? x * lb[j] : -x;
151 double max_term = use_bounds ? x * ub[j] : x;
152 ReorderAndCapTerms(&min_term, &max_term);
154 static_cast<int64_t
>(std::round(ldexp(min_term, factor_exponent)));
156 static_cast<int64_t
>(std::round(ldexp(max_term, factor_exponent)));
158 if (sum_min > max_absolute_sum || sum_max > max_absolute_sum) {
161 recompute_sum =
false;
165 *scaling_factor = ldexp(1.0, factor_exponent);
171 const std::vector<double>& lb,
172 const std::vector<double>& ub,
double scaling_factor,
174 double* max_scaled_sum_error) {
175 ComputeScalingErrors<true>(
input, lb, ub, scaling_factor,
180 const std::vector<double>& lb,
181 const std::vector<double>& ub,
182 int64_t max_absolute_sum) {
183 double scaling_factor;
184 GetBestScalingOfDoublesToInt64<true>(
input, lb, ub, max_absolute_sum,
186 return scaling_factor;
190 int64_t max_absolute_sum,
191 double* scaling_factor,
193 double max_scaled_sum_error;
194 GetBestScalingOfDoublesToInt64<false>(
input, {}, {}, max_absolute_sum,
196 ComputeScalingErrors<false>(
input, {}, {}, *scaling_factor,
201 double scaling_factor) {
203 for (
int i = 0; i < x.size() && gcd != 1; ++i) {
204 int64_t
value = std::abs(std::round(x[i] * scaling_factor));
206 if (
value == 0)
continue;
213 const int64_t r = gcd %
value;
219 return gcd > 0 ? gcd : 1;
223 static_assert(CHAR_BIT == 8);
224 static_assert(
sizeof(double) == 8);
226 const uint64_t bit_rep =
227 absl::little_endian::FromHost64(absl::bit_cast<uint64_t>(
value));
228 return static_cast<int>((bit_rep >> 52) & 0x7FF) - 1023;
232 mutable_value =
fast_scalbn(mutable_value, exponent);
236 if (
value == 0.0)
return 0.0;
238 absl::little_endian::FromHost64(absl::bit_cast<uint64_t>(
value));
240 constexpr uint64_t kExponentMask(0x7FF0000000000000);
244 const uint64_t value_exponent =
245 (bit_rep + (
static_cast<uint64_t
>(exponent) << 52)) & kExponentMask;
246 bit_rep &= ~kExponentMask;
247 bit_rep |= value_exponent;
248 return absl::bit_cast<double>(absl::little_endian::ToHost64(bit_rep));
#define DCHECK_LE(val1, val2)
#define DCHECK_GE(val1, val2)
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