21#include "absl/log/check.h"
22#include "absl/numeric/int128.h"
23#include "absl/status/status.h"
24#include "absl/status/statusor.h"
25#include "absl/strings/str_format.h"
26#include "absl/time/clock.h"
27#include "absl/time/time.h"
35template <
typename Int>
36Int InternalChoose(Int n, Int k) {
51constexpr int64_t
kint64max = std::numeric_limits<int64_t>::max();
62std::vector<int64_t> LastNThatDoesNotOverflowForAllK(
63 bool overflows_intermediate_computation) {
64 absl::Time start_time = absl::Now();
70 std::vector<int64_t> result = {
75 overflows_intermediate_computation
77 static_cast<int64_t
>(0.5 + std::pow(2.0, 63.0 / 2))
82 for (int64_t k = 3;; ++k) {
83 const double max_log_comb = overflows_intermediate_computation
84 ? 63 * std::log(2) - std::log(k)
87 k, (1l << 23) - 1, [k, max_log_comb](int64_t n) {
90 if (result.back() < 2 * k) {
95 DCHECK_EQ(result.size(),
96 overflows_intermediate_computation
99 VLOG(1) <<
"LastNThatDoesNotOverflowForAllK(): " << absl::Now() - start_time;
103bool NChooseKIntermediateComputationOverflowsInt64(int64_t n, int64_t k) {
105 static const auto*
const result =
106 new std::vector<int64_t>(LastNThatDoesNotOverflowForAllK(
108 return k < result->size() ? n > (*result)[k] :
true;
111bool NChooseKResultOverflowsInt64(int64_t n, int64_t k) {
113 static const auto*
const result =
114 new std::vector<int64_t>(LastNThatDoesNotOverflowForAllK(
116 return k < result->size() ? n > (*result)[k] :
true;
120absl::StatusOr<int64_t>
NChooseK(int64_t n, int64_t k) {
122 return absl::InvalidArgumentError(absl::StrFormat(
"n is negative (%d)", n));
125 return absl::InvalidArgumentError(absl::StrFormat(
"k is negative (%d)", k));
128 return absl::InvalidArgumentError(
129 absl::StrFormat(
"k=%d is greater than n=%d", k, n));
134 if (k > n / 2) k = n - k;
135 if (!NChooseKIntermediateComputationOverflowsInt64(n, k)) {
136 return InternalChoose<int64_t>(n, k);
138 if (NChooseKResultOverflowsInt64(n, k)) {
139 return absl::InvalidArgumentError(
140 absl::StrFormat(
"(%d choose %d) overflows int64", n, k));
142 return static_cast<int64_t
>(InternalChoose<absl::int128>(n, k));
static double LogCombinations(int n, int k)
In SWIG mode, we don't want anything besides these top-level includes.
absl::StatusOr< int64_t > NChooseK(int64_t n, int64_t k)
Point BinarySearch(Point x_true, Point x_false, std::function< bool(Point)> f)
static const int64_t kint64max