27#include "absl/base/casts.h"
28#include "absl/base/internal/endian.h"
29#include "absl/log/check.h"
30#include "absl/types/span.h"
37void ReorderAndCapTerms(
double*
min,
double*
max) {
39 if (*
min > 0.0) *
min = 0.0;
40 if (*
max < 0.0) *
max = 0.0;
43template <
bool use_bounds>
45 absl::Span<const double> lb,
46 absl::Span<const double> ub,
double scaling_factor,
48 double* max_scaled_sum_error) {
49 double max_error = 0.0;
50 double min_error = 0.0;
53 for (
int i = 0;
i <
size; ++
i) {
55 if (
x == 0.0)
continue;
56 const double scaled =
x * scaling_factor;
65 const double error = std::round(scaled) - scaled;
66 const double error_lb = (use_bounds ? error * lb[
i] : -error);
67 const double error_ub = (use_bounds ? error * ub[
i] : error);
68 max_error += std::max(error_lb, error_ub);
69 min_error += std::min(error_lb, error_ub);
71 *max_scaled_sum_error = std::max(std::abs(max_error), std::abs(min_error));
74template <
bool use_bounds>
76 absl::Span<const double> lb,
77 absl::Span<const double> ub,
78 int64_t max_absolute_sum,
79 double* scaling_factor) {
80 const double kInfinity = std::numeric_limits<double>::infinity();
86 if (max_absolute_sum < 0)
return;
94 int factor_exponent = 0;
97 bool recompute_sum =
false;
98 bool is_first_value =
true;
101 for (
int i = 0;
i <
size; ++
i) {
103 double min_term = use_bounds ?
x * lb[
i] : -
x;
104 double max_term = use_bounds ?
x * ub[
i] :
x;
105 ReorderAndCapTerms(&min_term, &max_term);
108 if (!(min_term > -kInfinity && max_term < kInfinity))
return;
112 if (min_term == 0.0 && max_term == 0.0)
continue;
116 const double c = std::max(-min_term, max_term);
117 int candidate = msb - ilogb(c);
118 if (candidate >= std::numeric_limits<double>::max_exponent) {
119 candidate = std::numeric_limits<double>::max_exponent - 1;
121 if (std::round(ldexp(std::abs(c), candidate)) > max_absolute_sum) {
124 DCHECK_LE(std::abs(
static_cast<int64_t
>(round(ldexp(c, candidate)))),
128 if (is_first_value || candidate < factor_exponent) {
129 is_first_value =
false;
130 factor_exponent = candidate;
131 recompute_sum =
true;
135 static_cast<int64_t
>(std::round(ldexp(min_term, factor_exponent)));
137 static_cast<int64_t
>(std::round(ldexp(max_term, factor_exponent)));
138 if (sum_min >
static_cast<uint64_t
>(max_absolute_sum) ||
139 sum_max >
static_cast<uint64_t
>(max_absolute_sum)) {
141 recompute_sum =
true;
151 while (recompute_sum) {
154 for (
int j = 0; j <=
i; ++j) {
155 const double x =
input[j];
156 double min_term = use_bounds ?
x * lb[j] : -
x;
157 double max_term = use_bounds ?
x * ub[j] :
x;
158 ReorderAndCapTerms(&min_term, &max_term);
160 static_cast<int64_t
>(std::round(ldexp(min_term, factor_exponent)));
162 static_cast<int64_t
>(std::round(ldexp(max_term, factor_exponent)));
164 if (sum_min >
static_cast<uint64_t
>(max_absolute_sum) ||
165 sum_max >
static_cast<uint64_t
>(max_absolute_sum)) {
168 recompute_sum =
false;
172 *scaling_factor = ldexp(1.0, factor_exponent);
178 absl::Span<const double> lb,
179 absl::Span<const double> ub,
double scaling_factor,
181 double* max_scaled_sum_error) {
187 absl::Span<const double> lb,
188 absl::Span<const double> ub,
189 int64_t max_absolute_sum) {
190 double scaling_factor;
193 DCHECK(std::isfinite(scaling_factor));
194 return scaling_factor;
198 int64_t max_absolute_sum,
199 double* scaling_factor,
201 double max_scaled_sum_error;
206 DCHECK(std::isfinite(*scaling_factor));
210 double scaling_factor) {
211 DCHECK(std::isfinite(scaling_factor));
213 const int size =
static_cast<int>(
x.size());
214 for (
int i = 0; i <
size && gcd != 1; ++i) {
215 int64_t
value = std::abs(std::round(
x[i] * scaling_factor));
217 if (
value == 0)
continue;
224 const int64_t r = gcd %
value;
230 return gcd > 0 ? gcd : 1;
234 static_assert(CHAR_BIT == 8);
235 static_assert(
sizeof(double) == 8);
237 const uint64_t bit_rep =
238 absl::little_endian::FromHost64(absl::bit_cast<uint64_t>(
value));
239 return static_cast<int>((bit_rep >> 52) & 0x7FF) - 1023;
243 mutable_value =
fast_scalbn(mutable_value, exponent);
247 if (
value == 0.0)
return 0.0;
249 absl::little_endian::FromHost64(absl::bit_cast<uint64_t>(
value));
251 constexpr uint64_t kExponentMask(0x7FF0000000000000);
255 const uint64_t value_exponent =
256 (bit_rep + (
static_cast<uint64_t
>(exponent) << 52)) & kExponentMask;
257 bit_rep &= ~kExponentMask;
258 bit_rep |= value_exponent;
259 return absl::bit_cast<double>(absl::little_endian::ToHost64(bit_rep));
In SWIG mode, we don't want anything besides these top-level includes.
int fast_ilogb(double value)
double fast_scalbn(double value, int exponent)
double GetBestScalingOfDoublesToInt64(absl::Span< const double > input, absl::Span< const double > lb, absl::Span< const double > ub, int64_t max_absolute_sum)
void ComputeScalingErrors(absl::Span< const double > input, absl::Span< const double > lb, absl::Span< const double > ub, double scaling_factor, double *max_relative_coeff_error, double *max_scaled_sum_error)
int64_t ComputeGcdOfRoundedDoubles(absl::Span< const double > x, double scaling_factor)
void fast_scalbn_inplace(double &mutable_value, int exponent)
int MostSignificantBitPosition64(uint64_t n)
static int input(yyscan_t yyscanner)
double max_relative_coeff_error