finding quartiles - c++

I've written a program where the user can enter any number of values into a vector and it's supposed to return the quartiles, but I keep getting a "vector subscript out of range" error :
#include "stdafx.h"
#include <iostream>
#include <string>
#include <algorithm>
#include <iomanip>
#include <ios>
#include <vector>
int main () {
using namespace std;
cout << "Enter a list of numbers: ";
vector<double> quantile;
double x;
//invariant: homework contains all the homework grades so far
while (cin >> x)
quantile.push_back(x);
//check that the student entered some homework grades
//typedef vector<double>::size_type vec_sz;
int size = quantile.size();
if (size == 0) {
cout << endl << "You must enter your numbers . "
"Please try again." << endl;
return 1;
}
sort(quantile.begin(), quantile.end());
int mid = size/2;
double median;
median = size % 2 == 0 ? (quantile[mid] + quantile[mid-1])/2 : quantile[mid];
vector<double> first;
vector<double> third;
for (int i = 0; i!=mid; ++i)
{
first[i] = quantile[i];
}
for (int i = mid; i!= size; ++i)
{
third[i] = quantile[i];
}
double fst;
double trd;
int side_length = 0;
if (size % 2 == 0)
{
side_length = size/2;
}
else {
side_length = (size-1)/2;
}
fst = (size/2) % 2 == 0 ? (first[side_length/2]/2 + first[(side_length-1)/2])/2 : first[side_length/2];
trd = (size/2) % 2 == 0 ? (third[side_length/2]/2 + third[(side_length-1)/2])/2 : third[side_length/2];
streamsize prec = cout.precision();
cout << "The quartiles are" << setprecision(3) << "1st"
<< fst << "2nd" << median << "3rd" << trd << setprecision(prec) << endl;
return 0;
}

Instead of doing std::sort(quantile.begin(), quantile.end()) a somewhat cheaper way would be
auto const Q1 = quantile.size() / 4;
auto const Q2 = quantile.size() / 2;
auto const Q3 = Q1 + Q2;
std::nth_element(quantile.begin(), quantile.begin() + Q1, quantile.end());
std::nth_element(quantile.begin() + Q1 + 1, quantile.begin() + Q2, quantile.end());
std::nth_element(quantile.begin() + Q2 + 1, quantile.begin() + Q3, quantile.end());
This would not sort the complete array, but only do a "between groups" sort of the 4 quartile. This saves on the "within groups" sort that a full std::sort would do.
If your quantile array is not large, it's a small optimization. But the scaling behavior of std::nth_element is O(N) however, rather than O(N log N) of a std::sort.

Here is Quantile function which is MATLAB's equivalent with linear interpolation:
#include <algorithm>
#include <cmath>
#include <vector>
template<typename T>
static inline double Lerp(T v0, T v1, T t)
{
return (1 - t)*v0 + t*v1;
}
template<typename T>
static inline std::vector<T> Quantile(const std::vector<T>& inData, const std::vector<T>& probs)
{
if (inData.empty())
{
return std::vector<T>();
}
if (1 == inData.size())
{
return std::vector<T>(1, inData[0]);
}
std::vector<T> data = inData;
std::sort(data.begin(), data.end());
std::vector<T> quantiles;
for (size_t i = 0; i < probs.size(); ++i)
{
T poi = Lerp<T>(-0.5, data.size() - 0.5, probs[i]);
size_t left = std::max(int64_t(std::floor(poi)), int64_t(0));
size_t right = std::min(int64_t(std::ceil(poi)), int64_t(data.size() - 1));
T datLeft = data.at(left);
T datRight = data.at(right);
T quantile = Lerp<T>(datLeft, datRight, poi - left);
quantiles.push_back(quantile);
}
return quantiles;
}
Find quartiles:
std::vector<double> in = { 1,2,3,4,5,6,7,8,9,10,11 };
auto quartiles = Quantile<double>(in, { 0.25, 0.5, 0.75 });

This C++ template function calculates quartile for you. It assumes x to be sorted.
#include <assert.h>
template <typename T1, typename T2> typename T1::value_type quant(const T1 &x, T2 q)
{
assert(q >= 0.0 && q <= 1.0);
const auto n = x.size();
const auto id = (n - 1) * q;
const auto lo = floor(id);
const auto hi = ceil(id);
const auto qs = x[lo];
const auto h = (id - lo);
return (1.0 - h) * qs + h * x[hi];
}
To use it do:
std::vector<float> x{1,1,2,2,3,4,5,6};
std::cout << quant(x, 0.25) << std::endl;
std::cout << quant(x, 0.50) << std::endl;
std::cout << quant(x, 0.75) << std::endl;

You need to preallocate first and third vectors before you set the contents.
vector<double> first(mid);
vector<double> third(size-mid);
or use push_back instead of assignments to first[i] and third[i]

If only one element in vector, this instruction is out of range:
quantile[mid-1]
"i" starting from mid so third[0] is out of range
for (int i = mid; i!= size; ++i)
{
third[i] = quantile[i];
}

Here is one error:
vector<double> first;
vector<double> third;
for (int i = 0; i!=mid; ++i)
{
first[i] = quantile[i];
}
The vector first doesn't have any contents, but you try to access the contents. Same problem with third and its loop. Do you mean to use push_back instead?

Implementation for weighted quantiles
This implements a weight functionality for the quantile function with linear interpolation in between the gridpoints.
#include <vector>
#include <numeric>
#include <algorithm>
#include <iostream>
#include <assert.h>
// https://stackoverflow.com/a/12399290/7128154
template <typename T>
std::vector<size_t> sorted_index(const std::vector<T> &v) {
std::vector<size_t> idx(v.size());
iota(idx.begin(), idx.end(), 0);
stable_sort(idx.begin(), idx.end(),
[&v](size_t i1, size_t i2) {return v[i1] < v[i2];});
return idx;
}
// https://stackoverflow.com/a/1267878/7128154
template< typename order_iterator, typename value_iterator >
void reorder( order_iterator order_begin, order_iterator order_end, value_iterator v ) {
typedef typename std::iterator_traits< value_iterator >::value_type value_t;
typedef typename std::iterator_traits< order_iterator >::value_type index_t;
typedef typename std::iterator_traits< order_iterator >::difference_type diff_t;
diff_t remaining = order_end - 1 - order_begin;
for ( index_t s = index_t(), d; remaining > 0; ++ s ) {
for ( d = order_begin[s]; d > s; d = order_begin[d] ) ;
if ( d == s ) {
-- remaining;
value_t temp = v[s];
while ( d = order_begin[d], d != s ) {
swap( temp, v[d] );
-- remaining;
}
v[s] = temp;
}
}
}
// https://stackoverflow.com/a/1267878/7128154
template< typename order_iterator, typename value_iterator >
void reorder_destructive( order_iterator order_begin, order_iterator order_end, value_iterator v ) {
typedef typename std::iterator_traits< value_iterator >::value_type value_t;
typedef typename std::iterator_traits< order_iterator >::value_type index_t;
typedef typename std::iterator_traits< order_iterator >::difference_type diff_t;
diff_t remaining = order_end - 1 - order_begin;
for ( index_t s = index_t(); remaining > 0; ++ s ) {
index_t d = order_begin[s];
if ( d == (diff_t) -1 ) continue;
-- remaining;
value_t temp = v[s];
for ( index_t d2; d != s; d = d2 ) {
std::swap( temp, v[d] );
std::swap( order_begin[d], d2 = (diff_t) -1 );
-- remaining;
}
v[s] = temp;
}
}
// https://stackoverflow.com/a/29677616/7128154
// https://stackoverflow.com/a/37708864/7128154
template <typename T>
double quantile(double q, std::vector<T> values, std::vector<double> weights = std::vector<double>())
{
assert( 0. <= q && q <= 1. && "expecting quantile in range [0; 1]");
if (weights.empty())
{
weights = std::vector<double>(values.size(), 1.);
}
else
{
assert (values.size() == weights.size() && "values and weights missfit in quantiles");
std::vector<size_t> inds = sorted_index(values);
reorder_destructive(inds.begin(), inds.end(), weights.begin());
}
stable_sort(values.begin(), values.end());
// values and weights are sorted now
std::vector<double> quantiles (weights.size());
quantiles[0] = weights[0];
for (int ii = 1; ii < quantiles.size(); ii++)
{
quantiles[ii] = quantiles[ii-1] + weights[ii];
}
double norm = std::accumulate(weights.begin(), weights.end(), 0.0);
int ind = 0;
double qCurrent = 0;
for (; ind < quantiles.size(); ind++)
{
qCurrent = (quantiles[ind] - weights[ind] / 2. ) / norm;
quantiles[ind] = qCurrent;
if (qCurrent > q)
{
if (ind == 0) {return values[0];}
double rat = (q - quantiles[ind-1]) / (quantiles[ind] - quantiles[ind-1]);
return values[ind-1] + (values[ind] - values[ind-1]) * rat;
}
}
return values[values.size()-1];
}
template <typename T>
double quantile(double q, std::vector<T> values, std::vector<int> weights)
{
std::vector<double> weights_double (weights.begin(), weights.end());
return quantile(q, values, weights_double);
}
int main()
{
std::vector<int> vals {5, 15, 25, 35, 45, 55, 65, 75, 85, 95};
std::cout << "quantile(0, vals)=" << quantile(0, vals) << std::endl;
std::cout << "quantile(.73, vals)=" << quantile(.73, vals) << std::endl;
std::vector<int> vals2 {1, 2, 3};
std::vector<double> ws2 {1, 2, 3};
std::cout << "quantile(.13, vals2, ws2)=" << quantile(.13, vals2, ws2) << std::endl;
}
Output
quantile(0, vals)=5
quantile(.73, vals)=73
quantile(.13, vals2, ws2)=1.18667
About weighted quantiles
While in the unweighted case, the input values form an equidistant distribution
values: [1, 2, 3] -> positions: [1/6, 3/6, 5/6]
in the weighted case, the distance is modified.
values: [1, 2, 3], weights: [1, 2, 1] -> positions: [1/8, 4/8, 7/8]
This is not equivalent to a repetition of values for the unweighted case
values: [1, 2, 2, 3] -> positions: [1/8, 3/8, 5/8, 7/8],
as a plateau is formed in between the repeated values. This means:
quantile(q=3/8, values=[1, 2, 2, 3]) = 2
but
quantile(q=3/8, values=[1, 2, 3], weights=[1, 2, 1]) = 1.67

Related

What algorithm can I use in this liner function question?

Firstly, I would like to apologise for my bad English.
when I submit the code below to DomJudge I got TimeLimit ERROR.
I can't think of ways to solve this question albeit I searched all over the internet and still couldn't find a solution.
Can someone give me a hint?
Question:
Here are N linear function fi(x) = aix + bi, where 1 ≤ i ≤ N。Define F(x) = maxifi(x). Please compute
the following equation for the input c[i], where 1 ≤ i ≤ m.
**Σ(i=1 to m) F(c[i])**
For example, given 4 linear function as follows. f1(x) = –x, f2 = x, f3 = –2x – 3, f4 = 2x – 3. And the
input is c[1] = 4, c[2] = –5, c[3] = –1, c[4] = 0, c[5] = 2. We have F(c[1]) = 5, F(c[2]) = 7, F(c[3])
= 1, F(c[4]) = 0, F(c[5]) = 2. Then,
**Σ(i=1 to 5)𝐹(𝑐[𝑖])
= 𝐹(𝑐[1]) + 𝐹(𝑐[2]) + 𝐹(𝑐[3]) + 𝐹(𝑐[4]) + 𝐹([5]) = 5 + 7 + 1 + 0 + 2 = 15**
Input Format:
The first line contains two positive integers N and m. The next N lines will contain two integers ai
and bi, and the last line will contain m integers c[1], c[2], c[3],…, c[m]. Each element separated by
a space.
Output Format:
Please output the value of the above function.
question image:https://i.stack.imgur.com/6HeaA.png
Sample Input:
4 5
-1 0
1 0
-2 -3
2 -3
4 -5 -1 0 2
Sample Output:
15
My Program
#include <iostream>
#include <vector>
struct L
{
int a;
int b;
};
int main()
{
int n{ 0 };
int m{ 0 };
while (std::cin >> n >> m)
{
//input
std::vector<L> arrL(n);
for (int iii{ 0 }; iii < n; ++iii)
{
std::cin >> arrL[iii].a >> arrL[iii].b;
}
//find max in every linear polymore
int answer{ 0 };
for (int iii{ 0 }; iii < m; ++iii)
{
int input{ 0 };
int max{ 0 };
std::cin >> input;
max = arrL[0].a * input + arrL[0].b;
for (int jjj{ 1 }; jjj < n; ++jjj)
{
int tmp{arrL[jjj].a * input + arrL[jjj].b };
if (tmp > max)max = tmp;
}
answer += max;
}
//output
std::cout << answer << '\n';
}
return 0;
}
Your solution is O(n*m).
A faster solution is obtained by iteratively determinating the "dominating segments", and the correspong crossing points, called "anchors" in the following.
Each anchor is linked to two segments, on its left and on its right.
The first step consists in sorting the lines according to the a values, and then adding each new line iteratively.
When adding line i, we know that this line is dominant for large input values, and must be added (even if it will be removed in the following steps).
We calculate the intersection of this line with the previous added line:
if the intersection value is higher than the rightmost anchor, then we add a new anchor corresponding to this new line
if the intersection value is lower than the rightmost anchor, then we know that we have to suppress this last anchor value. In this case, we iterate the process, calculating now the intersection with the right segment of the previous anchor.
Complexity is dominated by sorting: O(nlogn + mlogm). The anchor determination process is O(n).
When we have the anchors, then determining the rigtht segment for each input x value is O(n+ m). If needed, this last value could be further reduced with a binary search (not implemented).
Compared to first version of the code, a few errors have been corrected. These errors were concerning some corner cases, with some identical lines at the extreme left (i.e. lowest values of a). Besides, random sequences have been generated (more than 10^7), for comparaison of the results with those obtained by OP's code. No differences were found. It is likely that if some errors remain, they correspond to other unknown corner cases. The algorithm by itself looks quite valid.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
// lines of equation `y = ax + b`
struct line {
int a;
int b;
friend std::ostream& operator << (std::ostream& os, const line& coef) {
os << "(" << coef.a << ", " << coef.b << ")";
return os;
}
};
struct anchor {
double x;
int segment_left;
int segment_right;
friend std::ostream& operator << (std::ostream& os, const anchor& anc) {
os << "(" << anc.x << ", " << anc.segment_left << ", " << anc.segment_right << ")";
return os;
}
};
// intersection of two lines
double intersect (line& seg1, line& seg2) {
double x;
x = double (seg1.b - seg2.b) / (seg2.a - seg1.a);
return x;
}
long long int max_funct (std::vector<line>& lines, std::vector<int> absc) {
long long int sum = 0;
auto comp = [&] (line& x, line& y) {
if (x.a == y.a) return x.b < y.b;
return x.a < y.a;
};
std::sort (lines.begin(), lines.end(), comp);
std::sort (absc.begin(), absc.end());
// anchors and dominating segments determination
int n = lines.size();
std::vector<anchor> anchors (n+1);
int n_anchor = 1;
int l0 = 0;
while ((l0 < n-1) && (lines[l0].a == lines[l0+1].a)) l0++;
int l1 = l0 + 1;
if (l0 == n-1) {
anchors[0] = {0.0, l0, l0};
} else {
while ((l1 < n-1) && (lines[l1].a == lines[l1+1].a)) l1++;
double x = intersect(lines[l0], lines[l1]);
anchors[0] = {x, l0, l1};
for (int i = l1 + 1; i < n; ++i) {
if ((i != (n-1)) && lines[i].a == lines[i+1].a) continue;
double x = intersect(lines[anchors[n_anchor-1].segment_right], lines[i]);
if (x > anchors[n_anchor-1].x) {
anchors[n_anchor].x = x;
anchors[n_anchor].segment_left = anchors[n_anchor - 1].segment_right;
anchors[n_anchor].segment_right = i;
n_anchor++;
} else {
n_anchor--;
if (n_anchor == 0) {
x = intersect(lines[anchors[0].segment_left], lines[i]);
anchors[0] = {x, anchors[0].segment_left, i};
n_anchor = 1;
} else {
i--;
}
}
}
}
// sum calculation
int j = 0; // segment index (always increasing)
for (int x: absc) {
while (j < n_anchor && anchors[j].x < x) j++;
line seg;
if (j == 0) {
seg = lines[anchors[0].segment_left];
} else {
if (j == n_anchor) {
if (anchors[n_anchor-1].x < x) {
seg = lines[anchors[n_anchor-1].segment_right];
} else {
seg = lines[anchors[n_anchor-1].segment_left];
}
} else {
seg = lines[anchors[j-1].segment_right];
}
}
sum += seg.a * x + seg.b;
}
return sum;
}
int main() {
std::vector<line> lines = {{-1, 0}, {1, 0}, {-2, -3}, {2, -3}};
std::vector<int> x = {4, -5, -1, 0, 2};
long long int sum = max_funct (lines, x);
std::cout << "sum = " << sum << "\n";
lines = {{1,0}, {2, -12}, {3, 1}};
x = {-3, -1, 1, 5};
sum = max_funct (lines, x);
std::cout << "sum = " << sum << "\n";
}
One possible issue is the loss of information when calculating the double x corresponding to line intersections, and therefoe to anchors. Here is a version using Rational to avoid such loss.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
struct Rational {
int p, q;
Rational () {p = 0; q = 1;}
Rational (int x, int y) {
p = x;
q = y;
if (q < 0) {
q -= q;
p -= p;
}
}
Rational (int x) {
p = x;
q = 1;
}
friend std::ostream& operator << (std::ostream& os, const Rational& x) {
os << x.p << "/" << x.q;
return os;
}
friend bool operator< (const Rational& x1, const Rational& x2) {return x1.p*x2.q < x1.q*x2.p;}
friend bool operator> (const Rational& x1, const Rational& x2) {return x2 < x1;}
friend bool operator<= (const Rational& x1, const Rational& x2) {return !(x1 > x2);}
friend bool operator>= (const Rational& x1, const Rational& x2) {return !(x1 < x2);}
friend bool operator== (const Rational& x1, const Rational& x2) {return x1.p*x2.q == x1.q*x2.p;}
friend bool operator!= (const Rational& x1, const Rational& x2) {return !(x1 == x2);}
};
// lines of equation `y = ax + b`
struct line {
int a;
int b;
friend std::ostream& operator << (std::ostream& os, const line& coef) {
os << "(" << coef.a << ", " << coef.b << ")";
return os;
}
};
struct anchor {
Rational x;
int segment_left;
int segment_right;
friend std::ostream& operator << (std::ostream& os, const anchor& anc) {
os << "(" << anc.x << ", " << anc.segment_left << ", " << anc.segment_right << ")";
return os;
}
};
// intersection of two lines
Rational intersect (line& seg1, line& seg2) {
assert (seg2.a != seg1.a);
Rational x = {seg1.b - seg2.b, seg2.a - seg1.a};
return x;
}
long long int max_funct (std::vector<line>& lines, std::vector<int> absc) {
long long int sum = 0;
auto comp = [&] (line& x, line& y) {
if (x.a == y.a) return x.b < y.b;
return x.a < y.a;
};
std::sort (lines.begin(), lines.end(), comp);
std::sort (absc.begin(), absc.end());
// anchors and dominating segments determination
int n = lines.size();
std::vector<anchor> anchors (n+1);
int n_anchor = 1;
int l0 = 0;
while ((l0 < n-1) && (lines[l0].a == lines[l0+1].a)) l0++;
int l1 = l0 + 1;
if (l0 == n-1) {
anchors[0] = {0.0, l0, l0};
} else {
while ((l1 < n-1) && (lines[l1].a == lines[l1+1].a)) l1++;
Rational x = intersect(lines[l0], lines[l1]);
anchors[0] = {x, l0, l1};
for (int i = l1 + 1; i < n; ++i) {
if ((i != (n-1)) && lines[i].a == lines[i+1].a) continue;
Rational x = intersect(lines[anchors[n_anchor-1].segment_right], lines[i]);
if (x > anchors[n_anchor-1].x) {
anchors[n_anchor].x = x;
anchors[n_anchor].segment_left = anchors[n_anchor - 1].segment_right;
anchors[n_anchor].segment_right = i;
n_anchor++;
} else {
n_anchor--;
if (n_anchor == 0) {
x = intersect(lines[anchors[0].segment_left], lines[i]);
anchors[0] = {x, anchors[0].segment_left, i};
n_anchor = 1;
} else {
i--;
}
}
}
}
// sum calculation
int j = 0; // segment index (always increasing)
for (int x: absc) {
while (j < n_anchor && anchors[j].x < x) j++;
line seg;
if (j == 0) {
seg = lines[anchors[0].segment_left];
} else {
if (j == n_anchor) {
if (anchors[n_anchor-1].x < x) {
seg = lines[anchors[n_anchor-1].segment_right];
} else {
seg = lines[anchors[n_anchor-1].segment_left];
}
} else {
seg = lines[anchors[j-1].segment_right];
}
}
sum += seg.a * x + seg.b;
}
return sum;
}
long long int max_funct_op (const std::vector<line> &arrL, const std::vector<int> &x) {
long long int answer = 0;
int n = arrL.size();
int m = x.size();
for (int i = 0; i < m; ++i) {
int input = x[i];
int vmax = arrL[0].a * input + arrL[0].b;
for (int jjj = 1; jjj < n; ++jjj) {
int tmp = arrL[jjj].a * input + arrL[jjj].b;
if (tmp > vmax) vmax = tmp;
}
answer += vmax;
}
return answer;
}
int main() {
long long int sum, sum_op;
std::vector<line> lines = {{-1, 0}, {1, 0}, {-2, -3}, {2, -3}};
std::vector<int> x = {4, -5, -1, 0, 2};
sum_op = max_funct_op (lines, x);
sum = max_funct (lines, x);
std::cout << "sum = " << sum << " sum_op = " << sum_op << "\n";
}
To reduce the time complexity from O(n*m) to something near O(nlogn), we need to order the input data in some way.
The m points where the target function is sampled can be easily sorted using std::sort, which has an O(mlogm) complexity in terms of comparisons.
Then, instead of searching the max between all the lines for each point, we can take advantage of a divide-and-conquer technique.
Some considerations can be made in order to create such an algorithm.
If there are no lines or no sample points, the answer is 0.
If there is only one line, we can evaluate it at each point, accumulating the values and return the result. In case of two lines we could easily accumulate the max between two values. Searching for the intersection and then separating the intervals to accumulate only the correct value may be more complicated, with multiple corner cases and overflow issues.
A recursive function accepting a list of lines, points and two special lines left and right, may start by calculating the middle point in the set of points. Then it could find the two lines (or the only one) that have the greater value at that point. One of them also have the greatest slope between all the ones passing for that maximum point, that would be the top "right". The other one, the top "left" (which may be the same one), have the least slope.
We can partition all the remaining lines in three sets.
All the lines having a greater slope than the "top right" one (but lower intercept). Those are the ones that we need to evaluate the sum for the subset of points at the right of the middle point.
All the lines having a lower slope than the "top left" one (but lower intercept). Those are the ones that we need to evaluate the sum for the subset of points at the left of the middle point.
The remaining lines, that won't partecipate anymore and can be removed. Note this includes both "top right" and "top left".
Having splitted both the points and the lines, we can recurively call the same function passing those subsets, along with the previous left line and "top left" as left and right to the left, and the "top right" line with the previous right as left and right to the right.
The return value of this function is the sum of the value at the middle point plus the return values of the two recursive calls.
To start the procedure, we don't need to evaluate the correct left and right at the extreme points, we can use an helper function as entry point which sorts the points and calls the recursive function passing all the lines, the points and two dummy values (the lowest possible line, y = 0 + std::numeric_limits<T>::min()).
The following is a possible implementation:
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
#include <limits>
struct Line
{
using value_type = long;
using result_type = long long;
value_type slope;
value_type intercept;
auto operator() (value_type x) const noexcept {
return static_cast<result_type>(x) * slope + intercept;
}
static constexpr Line min() noexcept {
return { 0, std::numeric_limits<value_type>::min()};
}
};
auto result_less_at(Line::value_type x)
{
return [x] (Line const& a, Line const& b) { return a(x) < b(x); };
}
auto slope_less_than(Line::value_type slope)
{
return [slope] (Line const& line) { return line.slope < slope; };
}
auto slope_greater_than(Line::value_type slope)
{
return [slope] (Line const& line) { return slope < line.slope; };
}
auto accumulate_results(Line const& line)
{
return [line] (Line::result_type acc, Line::value_type x) {
return acc + line(x);
};
}
struct find_max_lines_result_t
{
Line::result_type y_max;
Line left, right;
};
template< class LineIt, class XType >
auto find_max_lines( LineIt first_line, LineIt last_line
, Line left, Line right
, XType x )
{
auto result{ [left, right] (const auto max_left, const auto max_right)
-> find_max_lines_result_t {
if ( max_left < max_right )
return { max_right, right, right };
else if ( max_right < max_left )
return { max_left, left, left };
else
return { max_left, left, right };
}(left(x), right(x))
};
std::for_each( first_line, last_line
, [x, &result] (Line const& line) mutable {
auto const y{ line(x) };
if ( y == result.y_max ) {
if ( result.right.slope < line.slope )
result.right = line;
if ( line.slope < result.left.slope )
result.left = line;
}
else if ( result.y_max < y ) {
result = {y, line, line};
}
} );
return result;
}
template< class SampleIt >
auto sum_left_right_values( SampleIt const first_x, SampleIt const last_x
, Line const left, Line const right )
{
return std::accumulate( first_x, last_x, Line::result_type{},
[left, right] (Line::result_type acc, Line::value_type x) {
return acc + std::max(left(x), right(x)); } );
}
template< class LineIt, class XType >
auto find_max_result( LineIt const first_line, LineIt const last_line
, Line const left, Line const right
, XType const x )
{
auto const y_max{ std::max(left(x), right(x)) };
LineIt const max_line{ std::max_element(first_line, last_line, result_less_at(x)) };
return max_line == last_line ? y_max : std::max(y_max, (*max_line)(x));
}
template <class LineIt, class SampleIt>
auto sum_lines_max_impl( LineIt const first_line, LineIt const last_line,
SampleIt const first_x, SampleIt const last_x,
Line const left, Line const right )
{
if ( first_x == last_x ) {
return Line::result_type{};
}
if ( first_x + 1 == last_x ) {
return find_max_result(first_line, last_line, left, right, *first_x);
}
if ( first_line == last_line ) {
return sum_left_right_values(first_x, last_x, left, right);
}
auto const mid_x{ first_x + (last_x - first_x - 1) / 2 };
auto const top{ find_max_lines(first_line, last_line, left, right, *mid_x) };
auto const right_begin{ std::partition( first_line, last_line
, slope_less_than(top.left.slope) ) };
auto const right_end{ std::partition( right_begin, last_line
, slope_greater_than(top.right.slope) ) };
return top.y_max + sum_lines_max_impl( first_line, right_begin
, first_x, mid_x
, left, top.left )
+ sum_lines_max_impl( right_begin, right_end
, mid_x + 1, last_x
, top.right, right );
}
template <class LineIt, class SampleIt>
auto sum_lines_max( LineIt first_line, LineIt last_line
, SampleIt first_sample, SampleIt last_sample )
{
if ( first_line == last_line )
return Line::result_type{};
std::sort(first_sample, last_sample);
return sum_lines_max_impl( first_line, last_line
, first_sample, last_sample
, Line::min(), Line::min() );
}
int main()
{
std::vector<Line> lines{ {-1, 0}, {1, 0}, {-2, -3}, {2, -3} };
std::vector<long> points{ 4, -5, -1, 0, 2 };
std::cout << sum_lines_max( lines.begin(), lines.end()
, points.begin(), points.end() ) << '\n';
}
Testable here.

C++ Find all bases such that P in those bases ends with the decimal representation of Q

Given two numbers P and Q in decimal. Find all bases such that P in those bases ends with the decimal representation of Q.
#include <bits/stdc++.h>
using namespace std;
void convert10tob(int N, int b)
{
if (N == 0)
return;
int x = N % b;
N /= b;
if (x < 0)
N += 1;
convert10tob(N, b);
cout<< x < 0 ? x + (b * -1) : x;
return;
}
int countDigit(long long n)
{
if (n == 0)
return 0;
return 1 + countDigit(n / 10);
}
int main()
{
long P, Q;
cin>>P>>Q;
n = countDigit(Q);
return 0;
}
The idea in my mind was: I would convert P to other bases and check if P % pow(10, numberofdigits(B)) == B is true.
Well, I can check for some finite number of bases but how do I know where (after what base) to stop checking. I got stuck here.
For more clarity, here is an example: For P=71,Q=13 answer should be 68 and 4
how do I know where (after what base) to stop checking
Eventually, the base will become great enough that P will be represented with less digits than the number of decimal digits required to represent Q.
A more strict limit can be found considering the first base which produces a representation of P which is less than the one consisting of the decimal digits of Q. E.g. (71)10 = (12)69.
The following code shows a possible implementation.
#include <algorithm>
#include <cassert>
#include <iterator>
#include <vector>
auto digits_from( size_t n, size_t base )
{
std::vector<size_t> digits;
while (n != 0) {
digits.push_back(n % base);
n /= base;
}
if (digits.empty())
digits.push_back(0);
return digits;
}
auto find_bases(size_t P, size_t Q)
{
std::vector<size_t> bases;
auto Qs = digits_from(Q, 10);
// I'm using the digit with the max value to determine the starting base
auto it_max = std::max_element(Qs.cbegin(), Qs.cend());
assert(it_max != Qs.cend());
for (size_t base = *it_max + 1; ; ++base)
{
auto Ps = digits_from(P, base);
// We can stop when the base is too big
if (Ps.size() < Qs.size() ) {
break;
}
// Compare the first digits of P in this base with the ones of P
auto p_rbegin = std::reverse_iterator<std::vector<size_t>::const_iterator>(
Ps.cbegin() + Qs.size()
);
auto m = std::mismatch(Qs.crbegin(), Qs.crend(), p_rbegin, Ps.crend());
// All the digits match
if ( m.first == Qs.crend() ) {
bases.push_back(base);
}
// The digits form a number which is less than the one formed by Q
else if ( Ps.size() == Qs.size() && *m.first > *m.second ) {
break;
}
}
return bases;
}
int main()
{
auto bases = find_bases(71, 13);
assert(bases[0] == 4 && bases[1] == 68);
}
Edit
As noted by One Lyner, the previous brute force algorithm misses some corner cases and it's impractical for larger values of Q. In the following I'll address some of the possible optimizations.
Let's call m the number of decimal digit of Q, we want
(P)b = ... + qnbn + qn-1bn-1 + ... + q1b1 + q0 where m = n + 1
Different approaches can be explored, based on the number of digits of Q
Q has only one digit (so m = 1)
The previous equation reduces to
(P)b = q0
When P < q0 there are no solutions.
If P == q0 all the values greater than min(q0, 2) are valid solutions.
When P > q0 we have to check all (not really all, see the next item) the bases in [2, P - q0].
Q has only two digits (so m = 2)
Instead of checking all the possible candidates, as noted in One Lyner's answer, we can note that as we are searching the divisors of p = P - q0, we only need to test the values up to
bsqrt = sqrt(p) = sqrt(P - q0)
Because
if p % b == 0 than p / b is another divisor of p
The number of candidates can be ulteriorly limited using more sophisticated algorithms involving primes detection, as showed in One Lyner's answer. This will greatly reduce the running time of the search for the bigger values of P.
In the test program that follows I'll only limit the number of sample bases to bsqrt, when m <= 2.
The number of decimal digits of Q is greater than 2 (so m > 2)
We can introduce two more limit values
blim = mth root of P
It's the last radix producing a representation of P with more digits than Q. After that, there is only one radix such that
(P)b == qnbn + qn-1bn-1 + ... + q1b1 + q0
As P (and m) increases, blim becomes more and more smaller than bsqrt.
We can limit the search of the divisors up to blim and then find the last solution (if exists) in a few steps applying a root finding algorithm such as the Newton's method or a simple bisection one.
If big values are involved and fixed-sized numeric types are used, overflow is a concrete risk.
In the following program (admittedly quite convoluted), I tried to avoid it checking the calculations which produce the various roots and using a simple beisection method for the final step which doesn't evaluate the polynomial (like a Newton step would require), but just compares the digits.
#include <algorithm>
#include <cassert>
#include <cmath>
#include <climits>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <limits>
#include <optional>
#include <type_traits>
#include <vector>
namespace num {
template< class T
, typename std::enable_if_t<std::is_integral_v<T>, int> = 0 >
auto abs(T value)
{
if constexpr ( std::is_unsigned_v<T> ) {
return value;
}
using U = std::make_unsigned_t<T>;
// See e.g. https://stackoverflow.com/a/48612366/4944425
return U{ value < 0 ? (U{} - value) : (U{} + value) };
}
template <class T>
constexpr inline T sqrt_max {
std::numeric_limits<T>::max() >> (sizeof(T) * CHAR_BIT >> 1)
};
constexpr bool safe_sum(std::uintmax_t& a, std::uintmax_t b)
{
std::uintmax_t tmp = a + b;
if ( tmp <= a )
return false;
a = tmp;
return true;
}
constexpr bool safe_multiply(std::uintmax_t& a, std::uintmax_t b)
{
std::uintmax_t tmp = a * b;
if ( tmp / a != b )
return false;
a = tmp;
return true;
}
constexpr bool safe_square(std::uintmax_t& a)
{
if ( sqrt_max<std::uintmax_t> < a )
return false;
a *= a;
return true;
}
template <class Ub, class Ue>
auto safe_pow(Ub base, Ue exponent)
-> std::enable_if_t< std::is_unsigned_v<Ub> && std::is_unsigned_v<Ue>
, std::optional<Ub> >
{
Ub power{ 1 };
for (;;) {
if ( exponent & 1 ) {
if ( !safe_multiply(power, base) )
return std::nullopt;
}
exponent >>= 1;
if ( !exponent )
break;
if ( !safe_square(base) )
return std::nullopt;
}
return power;
}
template< class Ux, class Un>
auto nth_root(Ux x, Un n)
-> std::enable_if_t< std::is_unsigned_v<Ux> && std::is_unsigned_v<Un>
, Ux >
{
if ( n <= 1 ) {
if ( n < 1 ) {
std::cerr << "Domain error.\n";
return 0;
}
return x;
}
if ( x <= 1 )
return x;
std::uintmax_t nth_root = std::floor(std::pow(x, std::nextafter(1.0 / n, 1)));
// Rounding errors and overflows are possible
auto test = safe_pow(nth_root, n);
if (!test || test.value() > x )
return nth_root - 1;
test = safe_pow(nth_root + 1, n);
if ( test && test.value() <= x ) {
return nth_root + 1;
}
return nth_root;
}
constexpr inline size_t lowest_base{ 2 };
template <class N, class D = N>
auto to_digits( N n, D base )
{
std::vector<D> digits;
while ( n ) {
digits.push_back(n % base);
n /= base;
}
if (digits.empty())
digits.push_back(D{});
return digits;
}
template< class T >
T find_minimum_base(std::vector<T> const& digits)
{
assert( digits.size() );
return std::max( lowest_base
, digits.size() > 1
? *std::max_element(digits.cbegin(), digits.cend()) + 1
: digits.back() + 1);
}
template< class U, class Compare >
auto find_root(U low, Compare cmp) -> std::optional<U>
{
U high { low }, z{ low };
int result{};
while( (result = cmp(high)) < 0 ) {
z = high;
high *= 2;
}
if ( result == 0 ) {
return z;
}
low = z;
while ( low + 1 < high ) {
z = low + (high - low) / 2;
result = cmp(z);
if ( result == 0 ) {
return z;
}
if ( result < 0 )
low = z;
else if ( result > 0 )
high = z;
}
return std::nullopt;
}
namespace {
template< class NumberType > struct param_t
{
NumberType P, Q;
bool opposite_signs{};
public:
template< class Pt, class Qt >
param_t(Pt p, Qt q) : P{::num::abs(p)}, Q{::num::abs(q)}
{
if constexpr ( std::is_signed_v<Pt> )
opposite_signs = p < 0;
if constexpr ( std::is_signed_v<Qt> )
opposite_signs = opposite_signs != q < 0;
}
};
template< class NumberType > struct results_t
{
std::vector<NumberType> valid_bases;
bool has_infinite_results{};
};
template< class T >
std::ostream& operator<< (std::ostream& os, results_t<T> const& r)
{
if ( r.valid_bases.empty() )
os << "None.";
else if ( r.has_infinite_results )
os << "All the bases starting from " << r.valid_bases.back() << '.';
else {
for ( auto i : r.valid_bases )
os << i << ' ';
}
return os;
}
struct prime_factors_t
{
size_t factor, count;
};
} // End of unnamed namespace
auto prime_factorization(size_t n)
{
std::vector<prime_factors_t> factors;
size_t i = 2;
if (n % i == 0) {
size_t count = 0;
while (n % i == 0) {
n /= i;
count += 1;
}
factors.push_back({i, count});
}
for (size_t i = 3; i * i <= n; i += 2) {
if (n % i == 0) {
size_t count = 0;
while (n % i == 0) {
n /= i;
count += 1;
}
factors.push_back({i, count});
}
}
if (n > 1) {
factors.push_back({n, 1ull});
}
return factors;
}
auto prime_factorization_limited(size_t n, size_t max)
{
std::vector<prime_factors_t> factors;
size_t i = 2;
if (n % i == 0) {
size_t count = 0;
while (n % i == 0) {
n /= i;
count += 1;
}
factors.push_back({i, count});
}
for (size_t i = 3; i * i <= n && i <= max; i += 2) {
if (n % i == 0) {
size_t count = 0;
while (n % i == 0) {
n /= i;
count += 1;
}
factors.push_back({i, count});
}
}
if (n > 1 && n <= max) {
factors.push_back({n, 1ull});
}
return factors;
}
template< class F >
void apply_to_all_divisors( std::vector<prime_factors_t> const& factors
, size_t low, size_t high
, size_t index, size_t divisor, F use )
{
if ( divisor > high )
return;
if ( index == factors.size() ) {
if ( divisor >= low )
use(divisor);
return;
}
for ( size_t i{}; i <= factors[index].count; ++i) {
apply_to_all_divisors(factors, low, high, index + 1, divisor, use);
divisor *= factors[index].factor;
}
}
class ValidBases
{
using number_t = std::uintmax_t;
using digits_t = std::vector<number_t>;
param_t<number_t> param_;
digits_t Qs_;
results_t<number_t> results_;
public:
template< class Pt, class Qt >
ValidBases(Pt p, Qt q)
: param_{p, q}
{
Qs_ = to_digits(param_.Q, number_t{10});
search_bases();
}
auto& operator() () const { return results_; }
private:
void search_bases();
bool is_valid( number_t candidate );
int compare( number_t candidate );
};
void ValidBases::search_bases()
{
if ( param_.opposite_signs )
return;
if ( param_.P < Qs_[0] )
return;
number_t low = find_minimum_base(Qs_);
if ( param_.P == Qs_[0] ) {
results_.valid_bases.push_back(low);
results_.has_infinite_results = true;
return;
}
number_t P_ = param_.P - Qs_[0];
auto add_if_valid = [this](number_t x) mutable {
if ( is_valid(x) )
results_.valid_bases.push_back(x);
};
if ( Qs_.size() <= 2 ) {
auto factors = prime_factorization(P_);
apply_to_all_divisors(factors, low, P_, 0, 1, add_if_valid);
std::sort(results_.valid_bases.begin(), results_.valid_bases.end());
}
else {
number_t lim = std::max( nth_root(param_.P, Qs_.size())
, lowest_base );
auto factors = prime_factorization_limited(P_, lim);
apply_to_all_divisors(factors, low, lim, 0, 1, add_if_valid);
auto cmp = [this](number_t x) {
return compare(x);
};
auto b = find_root(lim + 1, cmp);
if ( b )
results_.valid_bases.push_back(b.value());
}
}
// Called only when P % candidate == Qs[0]
bool ValidBases::is_valid( number_t candidate )
{
size_t p = param_.P;
auto it = Qs_.cbegin();
while ( ++it != Qs_.cend() ) {
p /= candidate;
if ( p % candidate != *it )
return false;
}
return true;
}
int ValidBases::compare( number_t candidate )
{
auto Ps = to_digits(param_.P, candidate);
if ( Ps.size() < Qs_.size() )
return 1;
auto [ip, iq] = std::mismatch( Ps.crbegin(), Ps.crend()
, Qs_.crbegin());
if ( iq == Qs_.crend() )
return 0;
if ( *ip < *iq )
return 1;
return -1;
}
} // End of namespace 'num'
int main()
{
using Bases = num::ValidBases;
std::vector<std::pair<int, int>> tests {
{0,0}, {9, 9}, {3, 4}, {4, 0}, {4, 2}, {71, -4}, {71, 3}, {-71, -13},
{36, 100}, {172448, 12}, {172443, 123}
};
std::cout << std::setw(22) << "P" << std::setw(12) << "Q"
<< " valid bases\n\n";
for (auto sample : tests) {
auto [P, Q] = sample;
Bases a(P, Q);
std::cout << std::setw(22) << P << std::setw(12) << Q
<< " " << a() << '\n';
}
std::vector<std::pair<size_t, size_t>> tests_2 {
{49*25*8*81*11*17, 120}, {4894432871088700845ull, 13}, {18401055938125660803ull, 13},
{9249004726666694188ull, 19}, {18446744073709551551ull, 11}
};
for (auto sample : tests_2) {
auto [P, Q] = sample;
Bases a(P, Q);
std::cout << std::setw(22) << P << std::setw(12) << Q
<< " " << a() << '\n';
}
}
Testable here. Example of output:
P Q valid bases
0 0 All the bases starting from 2.
9 9 All the bases starting from 10.
3 4 None.
4 0 2 4
4 2 None.
71 -4 None.
71 3 4 17 34 68
-71 -13 4 68
36 100 3 2 6
172448 12 6 172446
172443 123 4
148440600 120 4
4894432871088700845 13 6 42 2212336518 4894432871088700842
18401055938125660803 13 13 17 23 18401055938125660800
9249004726666694188 19 9249004726666694179
18446744073709551551 11 2 18446744073709551550
To avoid the corner case P < 10 and P == Q having an infinity of bases solution, I'll assume you are only interested in bases B <= P.
Note that to have the last digit with the right value, you need P % B == Q % 10
which is equivalent to
B divides P - (Q % 10)
Let's use this fact to have a something more efficient.
#include <vector>
std::vector<size_t> find_divisors(size_t P) {
// returns divisors d of P, with 1 < d <= P
std::vector<size_t> D{P};
for(size_t i = 2; i <= P/i; ++i)
if (P % i == 0) {
D.push_back(i);
D.push_back(P/i);
}
return D;
}
std::vector<size_t> find_bases(size_t P, size_t Q) {
std::vector<size_t> bases;
for(size_t B: find_divisors(P - (Q % 10))) {
size_t p = P, q = Q;
while (q) {
if ((p % B) != (q % 10)) // checks digits are the same
break;
p /= B;
q /= 10;
}
if (q == 0) // all digits were equal
bases.push_back(B);
}
return bases;
}
#include <cstdio>
int main(int argc, char *argv[]) {
size_t P, Q;
sscanf(argv[1], "%zu", &P);
sscanf(argv[2], "%zu", &Q);
for(size_t B: find_bases(P, Q))
printf("%zu\n", B);
return 0;
}
The complexity is the same as finding all divisors of P - (Q%10), but you can't expect better, since if Q is a single digit, those are exactly the solutions.
Small benchmark:
> time ./find_bases 16285263 13
12
4035
16285260
0.00s user 0.00s system 54% cpu 0.005 total
Bigger numbers:
> time ./find_bases 4894432871088700845 13
6
42
2212336518
4894432871088700842
25.80s user 0.04s system 99% cpu 25.867 total
And following, with a more complicated but faster implementation to find all divisors of 64 bits numbers.
#include <cstdio>
#include <map>
#include <numeric>
#include <vector>
std::vector<size_t> find_divisors(size_t P) {
// returns divisors d of P, with 1 < d <= P
std::vector<size_t> D{P};
for(size_t i = 2; i <= P/i; ++i)
if (P % i == 0) {
D.push_back(i);
D.push_back(P/i);
}
return D;
}
size_t mulmod(size_t a, size_t b, size_t mod) {
return (__uint128_t)a * b % mod;
}
size_t modexp(size_t base, size_t exponent, size_t mod)
{
size_t x = 1, y = base;
while (exponent) {
if (exponent & 1)
x = mulmod(x, y, mod);
y = mulmod(y, y, mod);
exponent >>= 1;
}
return x % mod;
}
bool deterministic_isprime(size_t p)
{
static const unsigned char bases[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
// https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Testing_against_small_sets_of_bases
if (p < 2)
return false;
if (p != 2 && p % 2 == 0)
return false;
size_t s = (p - 1) >> __builtin_ctz(p-1);
for (size_t i = 0; i < sizeof(bases); i++) {
size_t a = bases[i], temp = s;
size_t mod = modexp(a, temp, p);
while (temp != p - 1 && mod != 1 && mod != p - 1) {
mod = mulmod(mod, mod, p);
temp *= 2;
}
if (mod != p - 1 && temp % 2 == 0)
return false;
}
return true;
}
size_t abs_diff(size_t x, size_t y) {
return (x > y) ? (x - y) : (y - x);
}
size_t pollard_rho(size_t n, size_t x0=2, size_t c=1) {
auto f = [n,c](size_t x){ return (mulmod(x, x, n) + c) % n; };
size_t x = x0, y = x0, g = 1;
while (g == 1) {
x = f(x);
y = f(f(y));
g = std::gcd(abs_diff(x, y), n);
}
return g;
}
std::vector<std::pair<size_t, size_t>> factorize_small(size_t &P) {
std::vector<std::pair<size_t, size_t>> factors;
if ((P & 1) == 0) {
size_t ctz = __builtin_ctzll(P);
P >>= ctz;
factors.emplace_back(2, ctz);
}
size_t i;
for(i = 3; i <= P/i; i += 2) {
if (i > (1<<22))
break;
size_t multiplicity = 0;
while ((P % i) == 0) {
++multiplicity;
P /= i;
}
if (multiplicity)
factors.emplace_back(i, multiplicity);
}
if (P > 1 && i > P/i) {
factors.emplace_back(P, 1);
P = 1;
}
return factors;
}
std::vector<std::pair<size_t, size_t>> factorize_big(size_t P) {
auto factors = factorize_small(P);
if (P == 1)
return factors;
if (deterministic_isprime(P)) {
factors.emplace_back(P, 1);
return factors;
}
std::map<size_t, size_t> factors_map;
factors_map.insert(factors.begin(), factors.end());
size_t some_factor = pollard_rho(P);
for(auto i: {some_factor, P/some_factor})
for(auto const& [p, expo]: factorize_big(i))
factors_map[p] += expo;
return {factors_map.begin(), factors_map.end()};
}
std::vector<size_t> all_divisors(size_t P) {
std::vector<size_t> divisors{1};
for(auto const& [p, expo]: factorize_big(P)) {
size_t ppow = p, previous_size = divisors.size();
for(size_t i = 0; i < expo; ++i, ppow *= p)
for(size_t j = 0; j < previous_size; ++j)
divisors.push_back(divisors[j] * ppow);
}
return divisors;
}
std::vector<size_t> find_bases(size_t P, size_t Q) {
if (P <= (Q%10))
return {};
std::vector<size_t> bases;
for(size_t B: all_divisors(P - (Q % 10))) {
if (B == 1)
continue;
size_t p = P, q = Q;
while (q) {
if ((p % B) != (q % 10)) // checks digits are the same
break;
p /= B;
q /= 10;
}
if (q == 0) // all digits were equal
bases.push_back(B);
}
return bases;
}
int main(int argc, char *argv[]) {
std::vector<std::pair<size_t, size_t>> tests;
if (argc > 1) {
size_t P, Q;
sscanf(argv[1], "%zu", &P);
sscanf(argv[2], "%zu", &Q);
tests.emplace_back(P, Q);
} else {
tests.assign({
{0,0}, {9, 9}, {3, 4}, {4, 0}, {4, 2}, {71, 3}, {71, 13},
{36, 100}, {172448, 12}, {172443, 123},
{49*25*8*81*11*17, 120}, {4894432871088700845ull, 13}, {18401055938125660803ull, 13},
{9249004726666694188ull, 19}
});
}
for(auto & [P, Q]: tests) {
auto bases = find_bases(P, Q);
if (tests.size() > 1)
printf("%zu, %zu: ", P, Q);
if (bases.empty()) {
printf(" None");
} else {
for(size_t B: bases)
printf("%zu ", B);
}
printf("\n");
}
return 0;
}
We now have:
> time ./find_bases
0, 0: None
9, 9: None
3, 4: None
4, 0: 2 4
4, 2: None
71, 3: 4 17 34 68
71, 13: 4 68
36, 100: 2 3 6
172448, 12: 6 172446
172443, 123: 4
148440600, 120: 4
4894432871088700845, 13: 6 42 2212336518 4894432871088700842
18401055938125660803, 13: 13 17 23 18401055938125660800
9249004726666694188, 19: 9249004726666694179 9249004726666694179
0.09s user 0.00s system 96% cpu 0.093 total
Fast as can be :)
(NB: this would be around 10 seconds with the answer from Bob__ )

Is there in OpenCV operation that is like op1:op2 in Matlab? [duplicate]

How can I do the equivalent of the following using C++/STL? I want to fill a std::vector with a range of values [min, max).
# Python
>>> x = range(0, 10)
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
I suppose I could use std::generate_n and provide a functor to generate the sequence, but I was wondering if there is a more succinct way of doing this using STL?
In C++11, there's std::iota:
#include <vector>
#include <numeric> //std::iota
int main() {
std::vector<int> x(10);
std::iota(std::begin(x), std::end(x), 0); //0 is the starting number
}
C++20 introduced a lazy version (just like Python) as part of the ranges library:
#include <iostream>
#include <ranges>
namespace views = std::views;
int main() {
for (int x : views::iota(0, 10)) {
std::cout << x << ' '; // 0 1 2 3 4 5 6 7 8 9
}
}
There is boost::irange:
std::vector<int> x;
boost::push_back(x, boost::irange(0, 10));
I ended up writing some utility functions to do this. You can use them as follows:
auto x = range(10); // [0, ..., 9]
auto y = range(2, 20); // [2, ..., 19]
auto z = range(10, 2, -2); // [10, 8, 6, 4]
The code:
#include <vector>
#include <stdexcept>
template <typename IntType>
std::vector<IntType> range(IntType start, IntType stop, IntType step)
{
if (step == IntType(0))
{
throw std::invalid_argument("step for range must be non-zero");
}
std::vector<IntType> result;
IntType i = start;
while ((step > 0) ? (i < stop) : (i > stop))
{
result.push_back(i);
i += step;
}
return result;
}
template <typename IntType>
std::vector<IntType> range(IntType start, IntType stop)
{
return range(start, stop, IntType(1));
}
template <typename IntType>
std::vector<IntType> range(IntType stop)
{
return range(IntType(0), stop, IntType(1));
}
I've been using this library for this exact purpose for years:
https://github.com/klmr/cpp11-range
Works very well and the proxies are optimized out.
for (auto i : range(1, 5))
cout << i << "\n";
for (auto u : range(0u))
if (u == 3u)
break;
else
cout << u << "\n";
for (auto c : range('a', 'd'))
cout << c << "\n";
for (auto i : range(100).step(-3))
if (i < 90)
break;
else
cout << i << "\n";
for (auto i : indices({"foo", "bar"}))
cout << i << '\n';
There is boost::irange, but it does not provide floating point, negative steps and can not directly initialize stl containers.
There is also numeric_range in my RO library
In RO, to initialize a vector:
vector<int> V=range(10);
Cut-n-paste example from doc page (scc - c++ snippet evaluator):
// [0,N) open-ended range. Only range from 1-arg range() is open-ended.
scc 'range(5)'
{0, 1, 2, 3, 4}
// [0,N] closed range
scc 'range(1,5)'
{1, 2, 3, 4, 5}
// floating point
scc 'range(1,5,0.5)'
{1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5}
// negative step
scc 'range(10,0,-1.5)'
{10, 8.5, 7, 5.5, 4, 2.5, 1}
// any arithmetic type
scc "range('a','z')"
a b c d e f g h i j k l m n o p q r s t u v w x y z
// no need for verbose iota. (vint - vector<int>)
scc 'vint V = range(5); V'
{0, 1, 2, 3, 4}
// is lazy
scc 'auto NR = range(1,999999999999999999l); *find(NR.begin(), NR.end(), 5)'
5
// Classic pipe. Alogorithms are from std::
scc 'vint{3,1,2,3} | sort | unique | reverse'
{3, 2, 1}
// Assign 42 to 2..5
scc 'vint V=range(0,9); range(V/2, V/5) = 42; V'
{0, 1, 42, 42, 42, 5, 6, 7, 8, 9}
// Find (brute force algorithm) maximum of `cos(x)` in interval: `8 < x < 9`:
scc 'range(8, 9, 0.01) * cos || max'
-0.1455
// Integrate sin(x) from 0 to pi
scc 'auto d=0.001; (range(0,pi,d) * sin || add) * d'
2
// Total length of strings in vector of strings
scc 'vstr V{"aaa", "bb", "cccc"}; V * size || add'
9
// Assign to c-string, then append `"XYZ"` and then remove `"bc"` substring :
scc 'char s[99]; range(s) = "abc"; (range(s) << "XYZ") - "bc"'
aXYZ
// Hide phone number:
scc "str S=\"John Q Public (650)1234567\"; S|isdigit='X'; S"
John Q Public (XXX)XXXXXXX
For those who can't use C++11 or libraries:
vector<int> x(10,0); // 0 is the starting number, 10 is the range size
transform(x.begin(),x.end(),++x.begin(),bind2nd(plus<int>(),1)); // 1 is the increment
A range() function similar to below will help:
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
// define range function (only once)
template <typename T>
vector <T> range(T N1, T N2) {
vector<T> numbers(N2-N1);
iota(numbers.begin(), numbers.end(), N1);
return numbers;
}
vector <int> arr = range(0, 10);
vector <int> arr2 = range(5, 8);
for (auto n : arr) { cout << n << " "; } cout << endl;
// output: 0 1 2 3 4 5 6 7 8 9
for (auto n : arr2) { cout << n << " "; } cout << endl;
// output: 5 6 7
I don't know of a way to do it like in python but another alternative is obviously to for loop through it:
for (int i = range1; i < range2; ++i) {
x.push_back(i);
}
chris's answer is better though if you have c++11
If you can't use C++11, you can use std::partial_sum to generate numbers from 1 to 10. And if you need numbers from 0 to 9, you can then subtract 1 using transform:
std::vector<int> my_data( 10, 1 );
std::partial_sum( my_data.begin(), my_data.end(), my_data.begin() );
std::transform(my_data.begin(), my_data.end(), my_data.begin(), bind2nd(std::minus<int>(), 1));
Some time ago I wrote the following _range class, which behaves like Python range (put it to the "range.h"):
#pragma once
#include <vector>
#include <cassert>
template < typename T = size_t >
class _range
{
const T kFrom, kEnd, kStep;
public:
///////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////
//
// INPUT:
// from - Starting number of the sequence.
// end - Generate numbers up to, but not including this number.
// step - Difference between each number in the sequence.
//
// REMARKS:
// Parameters must be all positive or all negative
//
_range( const T from, const T end, const T step = 1 )
: kFrom( from ), kEnd( end ), kStep( step )
{
assert( kStep != 0 );
assert( ( kFrom >= 0 && kEnd > 0 && kStep > 0 ) || ( kFrom < 0 && kEnd < 0 && kStep < 0 ) );
}
// Default from==0, step==1
_range( const T end )
: kFrom( 0 ), kEnd( end ), kStep( 1 )
{
assert( kEnd > 0 );
}
public:
class _range_iter
{
T fVal;
const T kStep;
public:
_range_iter( const T v, const T step ) : fVal( v ), kStep( step ) {}
operator T () const { return fVal; }
operator const T & () { return fVal; }
const T operator * () const { return fVal; }
const _range_iter & operator ++ () { fVal += kStep; return * this; }
bool operator == ( const _range_iter & ri ) const
{
return ! operator != ( ri );
}
bool operator != ( const _range_iter & ri ) const
{
// This is a tricky part - when working with iterators
// it checks only once for != which must be a hit to stop;
// However, this does not work if increasing kStart by N times kSteps skips over kEnd
return fVal < 0 ? fVal > ri.fVal : fVal < ri.fVal;
}
};
const _range_iter begin() { return _range_iter( kFrom, kStep ); }
const _range_iter end() { return _range_iter( kEnd, kStep ); }
public:
// Conversion to any vector< T >
operator std::vector< T > ( void )
{
std::vector< T > retRange;
for( T i = kFrom; i < kEnd; i += kStep )
retRange.push_back( i );
return retRange; // use move semantics here
}
};
// A helper to use pure range meaning _range< size_t >
typedef _range<> range;
And some test code looks like the following one:
#include "range.h"
#include <iterator>
#include <fstream>
using namespace std;
void RangeTest( void )
{
ofstream ostr( "RangeTest.txt" );
if( ostr.is_open() == false )
return;
// 1:
ostr << "1st test:" << endl;
vector< float > v = _range< float >( 256 );
copy( v.begin(), v.end(), ostream_iterator< float >( ostr, ", " ) );
// 2:
ostr << endl << "2nd test:" << endl;
vector< size_t > v_size_t( range( 0, 100, 13 ) );
for( auto a : v_size_t )
ostr << a << ", ";
// 3:
ostr << endl << "3rd test:" << endl;
auto vvv = range( 123 ); // 0..122 inclusive, with step 1
for( auto a : vvv )
ostr << a << ", ";
// 4:
ostr << endl << "4th test:" << endl;
// Can be used in the nested loops as well
for( auto i : _range< float >( 0, 256, 16.5 ) )
{
for( auto j : _range< int >( -2, -16, -3 ) )
{
ostr << j << ", ";
}
ostr << endl << i << endl;
}
}
As an iterator:
#include <iostream>
class Range {
int x, y, z;
public:
Range(int x) {this->x = 0; this->y = x; this->z = 1;}
Range(int x, int y) {this->x = x; this->y = y; this->z = 1;}
Range(int x, int y, int z) {this->x = x; this->y = y; this->z = z;}
struct Iterator
{
Iterator (int val, int inc) : val{val}, inc{inc} {}
Iterator& operator++(){val+=inc; return *this;}
int operator*() const {return val;}
friend bool operator!=(const Iterator& a, const Iterator& b){return a.val < b.val;}
private:
int val, inc;
};
Iterator begin() {return Iterator(x,z);}
Iterator end() {return Iterator(y,z);}
};
int main() {
for (auto i: Range(10))
{
std::cout << i << ' '; //0 1 2 3 4 5 6 7 8 9
}
std::cout << '\n';
for (auto i: Range(1,10))
{
std::cout << i << ' '; //1 2 3 4 5 6 7 8 9
}
std::cout << '\n';
for (auto i: Range(-10,10,3))
{
std::cout << i << ' '; //-10 -7 -4 -1 2 5 8
}
return 0;
}

Custom binary search in vector

Suppose I have a vector<int> myVec. Let there be n elements in it. I know that these elements are in sorted order(ascending) and also that they are unique. Let n = 10 and myVec be {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}. I'm given l and r such that 0<=l<=r<=n-1. Now i want to search an element val in the subvector that is defined by the bounds l and rsuch that
if val is found return val
if val is not found then return (if possible) a value in the subvector which is just smaller than val.
Return false(or -1 maybe) if either of the above is not possible.
In the above case if if l = 3 and r = 5. The subvector is {8, 10, 12}. If val = 8 return 8. If val = 7 return false (or -1). If val = 9 return 8.
How do I implement this. I want order comparable to binary search. Also, is it possible to use std::binary_search() present under algorithm header file.
something like this?
int search(int l, int r, int value) {
if (l > vec.Size() || r > vec.Size() || l > r) return -1;
for (int i = r; i >= l; --i) {
int v = vector[i];
if (v <= value) return v;
}
return -1;
}
or does it need to be binary?
int BinarySearch(int l, int r, int value) {
return PrivateBinarySearch(l, r, (l+r)/2, value);
}
int PrivateBinarySearch(int l, int r, int index, int value) {
if (vector[index] == value) return value;
else if (vector[index] > value) {
if (index == l) return -1;
else if (index == r) return -1;
else return PrivateBinarySearch(l, index, (index-1+l)/2, value);
}
else { // vector[index] < value
if (index == l) return vector[index];
else if (index == r) return vector[index];
else return PrivateBinarySearch(index, r, (index+1+r)/2, value);
}
Hope this helps
This should work for you and is pretty extensible and flexible:
template<typename T>
typename vector<T>::const_iterator
find_or_under (typename vector<T>::const_iterator start, typename vector<T>::const_iterator end,
const T& val)
{
auto el = std::lower_bound(start, end, val);
//if not found, propagate
if (el == end)
return el;
//if it's equal, just return the iterator
if ((*el) == val)
return el;
//if there is no value of an equal or smaller size, return the end
if (el == start)
return end;
//otherwise, return the previous element
return el-1;
}
//Functor representing the search
struct CustomSearch
{
//Create a searcher from a subrange
CustomSearch (const vector<int> &v, size_t l, size_t r)
{
start = std::lower_bound(std::begin(v), std::end(v), l);
end = find_or_under(start, std::end(v), r) + 1;
}
//Calling the searcher
//Returns this->end on not found
auto operator() (int val)
{
return find_or_under(start, end, val);
}
vector<int>::const_iterator start;
vector<int>::const_iterator end;
};
int main() {
vector<int> v = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
CustomSearch searcher {v, 3, 8};
cout << *searcher(6);
}
Using traditional binary search with minor modification:
#include <iostream>
#include <vector>
int search(const std::vector<int> &vec, int l, int r, int val)
{
int pivot, xl = l, xr = r, mid;
do {
/* Not exact match, check if the closest lower match is in the
* subvector. */
if (xl > xr) {
return xr >= l ? vec[xr]: -1;
}
mid = (xl + xr) / 2;
pivot = vec[mid];
if (val < pivot) {
xr = mid - 1;
} else if (val > pivot) {
xl = mid + 1;
} else if (val == pivot) {
return val;
}
} while (true);
}
int main()
{
std::vector<int> myVec(10);
myVec[0] = 2;
myVec[1] = 4;
myVec[2] = 6;
myVec[3] = 8;
myVec[4] = 10;
myVec[5] = 12;
myVec[6] = 14;
myVec[7] = 16;
myVec[8] = 18;
myVec[9] = 20;
int l = 3, r = 5;
std::cout << "search(3, 5, 8) = " << search(myVec, 3, 5, 8) << std::endl;
std::cout << "search(3, 5, 7) = " << search(myVec, 3, 5, 7) << std::endl;
std::cout << "search(3, 5, 9) = " << search(myVec, 3, 5, 9) << std::endl;
return 0;
}
enter code here

Is there a compact equivalent to Python range() in C++/STL

How can I do the equivalent of the following using C++/STL? I want to fill a std::vector with a range of values [min, max).
# Python
>>> x = range(0, 10)
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
I suppose I could use std::generate_n and provide a functor to generate the sequence, but I was wondering if there is a more succinct way of doing this using STL?
In C++11, there's std::iota:
#include <vector>
#include <numeric> //std::iota
int main() {
std::vector<int> x(10);
std::iota(std::begin(x), std::end(x), 0); //0 is the starting number
}
C++20 introduced a lazy version (just like Python) as part of the ranges library:
#include <iostream>
#include <ranges>
namespace views = std::views;
int main() {
for (int x : views::iota(0, 10)) {
std::cout << x << ' '; // 0 1 2 3 4 5 6 7 8 9
}
}
There is boost::irange:
std::vector<int> x;
boost::push_back(x, boost::irange(0, 10));
I ended up writing some utility functions to do this. You can use them as follows:
auto x = range(10); // [0, ..., 9]
auto y = range(2, 20); // [2, ..., 19]
auto z = range(10, 2, -2); // [10, 8, 6, 4]
The code:
#include <vector>
#include <stdexcept>
template <typename IntType>
std::vector<IntType> range(IntType start, IntType stop, IntType step)
{
if (step == IntType(0))
{
throw std::invalid_argument("step for range must be non-zero");
}
std::vector<IntType> result;
IntType i = start;
while ((step > 0) ? (i < stop) : (i > stop))
{
result.push_back(i);
i += step;
}
return result;
}
template <typename IntType>
std::vector<IntType> range(IntType start, IntType stop)
{
return range(start, stop, IntType(1));
}
template <typename IntType>
std::vector<IntType> range(IntType stop)
{
return range(IntType(0), stop, IntType(1));
}
I've been using this library for this exact purpose for years:
https://github.com/klmr/cpp11-range
Works very well and the proxies are optimized out.
for (auto i : range(1, 5))
cout << i << "\n";
for (auto u : range(0u))
if (u == 3u)
break;
else
cout << u << "\n";
for (auto c : range('a', 'd'))
cout << c << "\n";
for (auto i : range(100).step(-3))
if (i < 90)
break;
else
cout << i << "\n";
for (auto i : indices({"foo", "bar"}))
cout << i << '\n';
There is boost::irange, but it does not provide floating point, negative steps and can not directly initialize stl containers.
There is also numeric_range in my RO library
In RO, to initialize a vector:
vector<int> V=range(10);
Cut-n-paste example from doc page (scc - c++ snippet evaluator):
// [0,N) open-ended range. Only range from 1-arg range() is open-ended.
scc 'range(5)'
{0, 1, 2, 3, 4}
// [0,N] closed range
scc 'range(1,5)'
{1, 2, 3, 4, 5}
// floating point
scc 'range(1,5,0.5)'
{1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5}
// negative step
scc 'range(10,0,-1.5)'
{10, 8.5, 7, 5.5, 4, 2.5, 1}
// any arithmetic type
scc "range('a','z')"
a b c d e f g h i j k l m n o p q r s t u v w x y z
// no need for verbose iota. (vint - vector<int>)
scc 'vint V = range(5); V'
{0, 1, 2, 3, 4}
// is lazy
scc 'auto NR = range(1,999999999999999999l); *find(NR.begin(), NR.end(), 5)'
5
// Classic pipe. Alogorithms are from std::
scc 'vint{3,1,2,3} | sort | unique | reverse'
{3, 2, 1}
// Assign 42 to 2..5
scc 'vint V=range(0,9); range(V/2, V/5) = 42; V'
{0, 1, 42, 42, 42, 5, 6, 7, 8, 9}
// Find (brute force algorithm) maximum of `cos(x)` in interval: `8 < x < 9`:
scc 'range(8, 9, 0.01) * cos || max'
-0.1455
// Integrate sin(x) from 0 to pi
scc 'auto d=0.001; (range(0,pi,d) * sin || add) * d'
2
// Total length of strings in vector of strings
scc 'vstr V{"aaa", "bb", "cccc"}; V * size || add'
9
// Assign to c-string, then append `"XYZ"` and then remove `"bc"` substring :
scc 'char s[99]; range(s) = "abc"; (range(s) << "XYZ") - "bc"'
aXYZ
// Hide phone number:
scc "str S=\"John Q Public (650)1234567\"; S|isdigit='X'; S"
John Q Public (XXX)XXXXXXX
For those who can't use C++11 or libraries:
vector<int> x(10,0); // 0 is the starting number, 10 is the range size
transform(x.begin(),x.end(),++x.begin(),bind2nd(plus<int>(),1)); // 1 is the increment
A range() function similar to below will help:
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
// define range function (only once)
template <typename T>
vector <T> range(T N1, T N2) {
vector<T> numbers(N2-N1);
iota(numbers.begin(), numbers.end(), N1);
return numbers;
}
vector <int> arr = range(0, 10);
vector <int> arr2 = range(5, 8);
for (auto n : arr) { cout << n << " "; } cout << endl;
// output: 0 1 2 3 4 5 6 7 8 9
for (auto n : arr2) { cout << n << " "; } cout << endl;
// output: 5 6 7
I don't know of a way to do it like in python but another alternative is obviously to for loop through it:
for (int i = range1; i < range2; ++i) {
x.push_back(i);
}
chris's answer is better though if you have c++11
If you can't use C++11, you can use std::partial_sum to generate numbers from 1 to 10. And if you need numbers from 0 to 9, you can then subtract 1 using transform:
std::vector<int> my_data( 10, 1 );
std::partial_sum( my_data.begin(), my_data.end(), my_data.begin() );
std::transform(my_data.begin(), my_data.end(), my_data.begin(), bind2nd(std::minus<int>(), 1));
Some time ago I wrote the following _range class, which behaves like Python range (put it to the "range.h"):
#pragma once
#include <vector>
#include <cassert>
template < typename T = size_t >
class _range
{
const T kFrom, kEnd, kStep;
public:
///////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////
//
// INPUT:
// from - Starting number of the sequence.
// end - Generate numbers up to, but not including this number.
// step - Difference between each number in the sequence.
//
// REMARKS:
// Parameters must be all positive or all negative
//
_range( const T from, const T end, const T step = 1 )
: kFrom( from ), kEnd( end ), kStep( step )
{
assert( kStep != 0 );
assert( ( kFrom >= 0 && kEnd > 0 && kStep > 0 ) || ( kFrom < 0 && kEnd < 0 && kStep < 0 ) );
}
// Default from==0, step==1
_range( const T end )
: kFrom( 0 ), kEnd( end ), kStep( 1 )
{
assert( kEnd > 0 );
}
public:
class _range_iter
{
T fVal;
const T kStep;
public:
_range_iter( const T v, const T step ) : fVal( v ), kStep( step ) {}
operator T () const { return fVal; }
operator const T & () { return fVal; }
const T operator * () const { return fVal; }
const _range_iter & operator ++ () { fVal += kStep; return * this; }
bool operator == ( const _range_iter & ri ) const
{
return ! operator != ( ri );
}
bool operator != ( const _range_iter & ri ) const
{
// This is a tricky part - when working with iterators
// it checks only once for != which must be a hit to stop;
// However, this does not work if increasing kStart by N times kSteps skips over kEnd
return fVal < 0 ? fVal > ri.fVal : fVal < ri.fVal;
}
};
const _range_iter begin() { return _range_iter( kFrom, kStep ); }
const _range_iter end() { return _range_iter( kEnd, kStep ); }
public:
// Conversion to any vector< T >
operator std::vector< T > ( void )
{
std::vector< T > retRange;
for( T i = kFrom; i < kEnd; i += kStep )
retRange.push_back( i );
return retRange; // use move semantics here
}
};
// A helper to use pure range meaning _range< size_t >
typedef _range<> range;
And some test code looks like the following one:
#include "range.h"
#include <iterator>
#include <fstream>
using namespace std;
void RangeTest( void )
{
ofstream ostr( "RangeTest.txt" );
if( ostr.is_open() == false )
return;
// 1:
ostr << "1st test:" << endl;
vector< float > v = _range< float >( 256 );
copy( v.begin(), v.end(), ostream_iterator< float >( ostr, ", " ) );
// 2:
ostr << endl << "2nd test:" << endl;
vector< size_t > v_size_t( range( 0, 100, 13 ) );
for( auto a : v_size_t )
ostr << a << ", ";
// 3:
ostr << endl << "3rd test:" << endl;
auto vvv = range( 123 ); // 0..122 inclusive, with step 1
for( auto a : vvv )
ostr << a << ", ";
// 4:
ostr << endl << "4th test:" << endl;
// Can be used in the nested loops as well
for( auto i : _range< float >( 0, 256, 16.5 ) )
{
for( auto j : _range< int >( -2, -16, -3 ) )
{
ostr << j << ", ";
}
ostr << endl << i << endl;
}
}
As an iterator:
#include <iostream>
class Range {
int x, y, z;
public:
Range(int x) {this->x = 0; this->y = x; this->z = 1;}
Range(int x, int y) {this->x = x; this->y = y; this->z = 1;}
Range(int x, int y, int z) {this->x = x; this->y = y; this->z = z;}
struct Iterator
{
Iterator (int val, int inc) : val{val}, inc{inc} {}
Iterator& operator++(){val+=inc; return *this;}
int operator*() const {return val;}
friend bool operator!=(const Iterator& a, const Iterator& b){return a.val < b.val;}
private:
int val, inc;
};
Iterator begin() {return Iterator(x,z);}
Iterator end() {return Iterator(y,z);}
};
int main() {
for (auto i: Range(10))
{
std::cout << i << ' '; //0 1 2 3 4 5 6 7 8 9
}
std::cout << '\n';
for (auto i: Range(1,10))
{
std::cout << i << ' '; //1 2 3 4 5 6 7 8 9
}
std::cout << '\n';
for (auto i: Range(-10,10,3))
{
std::cout << i << ' '; //-10 -7 -4 -1 2 5 8
}
return 0;
}