Dividing a data set almost equally among worker threads - c++

I have n number of elements and p number of threads. I am trying to divide the elements as equally as possible among the threads.
For example:
If n = 8 and p = 1, then [8]
If n = 8 and p = 2, then [4, 4]
If n = 8 and p = 3, then [2, 3, 3]
If n = 8 and p = 4, then [2, 2, 2, 2]
If n = 8 and p = 5, then [1, 1, 2, 2, 2]
If n = 8 and p = 6, then [1, 1, 1, 1, 2, 2]
If n = 8 and p = 7, then [1, 1, 1, 1, 1, 1, 2]
If n = 8 and p = 8, then [1, 1, 1, 1, 1, 1, 1, 1]
I cooked up a solution that almost works but not quite.
#include <vector>
#include <stdio.h>
#include <cmath>
int main(int argc, char **argv)
{
int p = 5;
const int SIZE = 8;
int i = 0;
int num = 0;
std::vector<int> iter;
if (p == 1)
iter.push_back(SIZE);
else
{
if (SIZE % p == 0)
{
num = SIZE / p;
for (i = 0; i < p; ++i)
iter.push_back(num);
}
else
{
num = (int)floor((float)SIZE / (float)p);
for (i = 0; i < p - 1; ++i)
iter.push_back(num);
iter.push_back((SIZE - (num * (p - 1))));
}
}
for (unsigned int j = 0; j < iter.size(); ++j)
printf("[%d] = %d\n", j, (int)iter[j]);
return 0;
}
Results produced with my solution:
If n = 8 and p = 1, then [8]
If n = 8 and p = 2, then [4, 4]
If n = 8 and p = 3, then [2, 2, 4]
If n = 8 and p = 4, then [2, 2, 2, 2]
If n = 8 and p = 5, then [1, 1, 1, 1, 4]
If n = 8 and p = 6, then [1, 1, 1, 1, 1, 3]
If n = 8 and p = 7, then [1, 1, 1, 1, 1, 1, 2]
If n = 8 and p = 8, then [1, 1, 1, 1, 1, 1, 1, 1]

try to think about this. if you have less objects then threads then each thread will get one object. if you have more objects then threads (buckets) then think about how would you divide 100 tennis balls to 8 buckets.
you could take 1 ball at a time and put that in the next bucket, once you passed all buckets you start from first bucket, this will make sure that at most the difference between each bucket size will be 1.
#include <vector>
#include <stdio.h>
int main(int argc, char **argv)
{
int p = 5;
const int SIZE = 8;
int p_size = SIZE > p ? p : SIZE;
std::vector<int> iter(p_size);
for (int i = 0; i < SIZE; i++)
{
iter[i%p_size] += 1;
}
for (unsigned int j = 0; j < iter.size(); ++j)
printf("[%d] = %d\n", j, (int)iter[j]);
return 0;
}

You can try this:
std::vector<int> iter(p);
std::generate(iter.begin(), iter.end(), [&]()
{
num += 1;
return SIZE / p + (num <= SIZE % p ? 1 : 0);
});
The first line creates the required number of elements, and the second operator fills this vector with actual data. It is written without explicit loops to make code more expressive.

This is less an answer to your specific question/problem, but more an alternative approach to your intended problem.
your solution is way to complicate... this code does the same, except the additional tasks are put into the front...
#include <iostream>
#include <vector>
int main(int argc, char **argv)
{
int p = 5;
const int n = 8;
// calculate number of tasks every thread have to do...
int every = n / p;
// calculate rest
int rest = n % p;
// initialize the vector with the number of tasks every thread have to do
std::vector<int> lst(p, every);
// split rest on the threads
for(int i=0; i<rest; ++i)
lst[i]++;
// print out
for(auto it : lst)
std::cout << it << ",";
return 0;
}
The trick is integer truncation, there is no need for floating point arithmetics, as you probably see, the other answers also do...

Related

Is there a way to sort a vector in segments?

If I have a vector with an odd number of elements and want to sort the vector in segments, how could I construct a loop that does this but doesn't access anything out of bounds?
Like an array like this:
[4, 5, 6, 3, 10, 2, 0] (size: 7)
And I want to sort in segments of 2, so it becomes like this:
[4, 5, 3, 6, 2, 10, 0]
I was thinking something like this, but then the vector would access arr[8] which is out of bounds.
for(int i = 0; i < arr.size(); i = i + 2) {
sort(arr.begin() + i, arr.begin() + i - 1);
}
Two options spring to mind:
First, you can constrain your loop:
const int SegmentLen = 2;
for (int i=0; i+SegmentLen-1 < arr.size(); i += SegmentLen)
std::sort(arr.begin()+i, arr.begin()+i+SegmentLen);
Second, you can loop a fixed number of times:
auto segments = arr.size() / SegmentLen;
for (int i=0; i < segments; ++i)
std::sort(arr.begin() + (i*SegmentLen), arr.begin() + (i*SegmentLen) + SegmentLen);
//Handle any leftovers
Just get the first even number less than or equal to the size of the array and then use that as the stop condition for the loop.
int main(){
std::array<int, 7> arr = {4, 5, 6, 3, 10, 2, 0};
auto size = arr.size() % 2 ? arr.size() - 1 : arr.size(); // if odd subtract one else use size
for (size_t i = 0; i < size - 2; i += 2)
std::sort(arr.begin() + i, arr.begin() + i + 2);
for (auto e : arr)
std::cout << e << " ";
}
Outputs:
4 5 3 6 10 2 0

Algorithms - Circular Array Rotation

Is this linear complexity implementation of circular array rotation correct?
n = number of elements
k = number of rotations
int write_to = 0;
int copy_current = 0;
int copy_final = a[0];
int rotation = k;
int position = 0;
for (int i = 0; i < n; i++) {
write_to = (position + rotation) % n;
copy_current = a[write_to];
a[write_to] = copy_final;
position = write_to;
copy_final = copy_current;
}
No.
Consider this example.
#include <iostream>
int main(void) {
int n = 6;
int k = 2;
int a[] = {1, 2, 3, 4, 5, 6};
int write_to = 0;
int copy_current = 0;
int copy_final = a[0];
int rotation = k;
int position = 0;
for (int i = 0; i < n; i++) {
write_to = (position + rotation) % n;
copy_current = a[write_to];
a[write_to] = copy_final;
position = write_to;
copy_final = copy_current;
}
for (int i = 0; i < n; i++) {
std::cout << a[i] << (i + 1 < n ? ' ' : '\n');
}
return 0;
}
Expected result:
5 6 1 2 3 4
Actual result:
3 2 1 4 1 6
Using stl::rotate on std::array, you can left rotate by, say 2, as:
std::array<int, 6> a{1, 2, 3, 4, 5, 6};
std::rotate(begin(a), begin(a) + 2, end(a)); // left rotate by 2
to yield: 3 4 5 6 1 2, or right-rotate by, say 2, as:
std::rotate(begin(a), end(a) - 2, end(a)); // right rotate by 2
to yield: 5 6 1 2 3 4, with linear complexity.
Rotate an Array of length n for k times in left or right directions.
The code is in Java
I define a Direction Enum:
public enum Direction {
L, R
};
Rotation with times and direction:
public static final void rotate(int[] arr, int times, Direction direction) {
if (arr == null || times < 0) {
throw new IllegalArgumentException("The array must be non-null and the order must be non-negative");
}
int offset = arr.length - times % arr.length;
if (offset > 0) {
int[] copy = arr.clone();
for (int i = 0; i < arr.length; ++i) {
int j = (i + offset) % arr.length;
if (Direction.R.equals(direction)) {
arr[i] = copy[j];
} else {
arr[j] = copy[i];
}
}
}
}
Complexity: O(n).
Example:
Input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Rotate 3 times left
Output: [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
Input: [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
Rotate 3 times right
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Fibonacci Sum of Large Numbers(Only Last Digit to be Printed)

I have been trying to come out with a solution regarding the problem of finding the last digit of the sum of large n Fibonacci series.
I have been able to pass several test cases with large n. But I'm stuck at the following case where n = 832564823476. I know it can be solved using Pisano's period but I'm unable to come out with a efficient algo. Any help would be great. Thanks.
My code that I have implemented is as follows-
#include <iostream>
using namespace std;
int calc_fib(int n) {
int fib[n+1];
fib[0]=0;
fib[1]=1;
int res = 1;
for(int i = 2; i<=n;i++){
fib[i] = (fib[i-1]%10 + fib[i-2]%10)%10;
res = res + fib[i];
}
return (res%10);
}
int main() {
int n = 0;
std::cin >> n;
std::cout << calc_fib(n) << '\n';
return 0;
}
SOLVED IT
Works on all range of inputs. It works on the following algorithm.
The idea is to notice that the last digits of fibonacci numbers also occur in sequences of length 60 (from the previous problem: since pisano peiod of 10 is 60). Irrespective of how large n is, its last digit is going to have appeared somewhere within the sequence.
Two Things apart from edge case of 10 as last digit.
Sum of nth Fibonacci series = F(n+2) -1
Then pisano period of module 10 = let n+2 mod (60) = m then find F(m) mod(10)-1
Code as follows;
#include <iostream>
using namespace std;
long long calc_fib(long long n) {
n = (n+2)%60;
int fib[n+1];
fib[0]=0;
fib[1]=1;
int res = 1;
for(int i = 2; i<=n;i++){
fib[i] = (fib[i-1]%10 + fib[i-2]%10)%10;
// res = res + fib[i];
}
// cout<<fib[n]<<"\n";
if(fib[n] == 0){
return 9;
}
return (fib[n]%10-1);
}
int main() {
long long n = 0;
std::cin >> n;
std::cout << calc_fib(n) << '\n';
return 0;
}
Actually it's even easier than Niall answer
int get_fibonacci_sum_last_digit(long long n) {
const int kPisanoSize = 60;
int rest = n % kPisanoSize;
int preparedNumbers[kPisanoSize] = {0, 1, 2, 4, 7, 2, 0, 3, 4, 8, 3,
2, 6, 9, 6, 6, 3, 0, 4, 5, 0, 6, 7, 4, 2, 7, 0, 8, 9, 8, 8, 7,
6, 4, 1, 6, 8, 5, 4, 0, 5, 6, 2, 9, 2, 2, 5, 8, 4, 3, 8, 2, 1,
4, 6, 1, 8, 0, 9, 0};
return preparedNumbers[rest];
}
If you only need to output the last digit as you said, I think you can just make use of the Pisano Period you mentioned, as for modular 10, the cycle length is only 60 and you can just pre-make an array of that 60 digits.
If you want to compute by yourself, I think you can use Matrix Exponentiation which gives you O(lg N) complexity, when calculating the matrix exponents, keep storing the temporary result modular 10. See the Matrices section for your reference.
For your function removing the array.
#include "stdafx.h"
#include <iostream>
using namespace std;
int calc_fib(long long int n) {
int fibzero = 0;
int fibone = 1;
int fibnext;
long long int res = 1;
for (long long int i = 2; i <= n; i++) {
fibnext = (fibone + fibzero) % 10;
fibzero = fibone;
fibone = fibnext;
res = res + fibnext;
}
return (res % 10);
}
int main()
{
long long int n = 0;
std::cin >> n;
std::cout << calc_fib(n) << '\n';
return 0;
}
Last digit of Fibonacci sum repeats after 60 elements.
Here the period is 60 [0-59].
So to get the last digit of n'th sum of number is the last digit of n%60'th sum of
number
#include <iostream>
#include <vector>
#include <algorithm>
int get_last_digit(int n){
std::vector<int> last_digits(60);
long long a = 0, b = 1;
last_digits[0] = 0;
last_digits[1] = 1;
long long temp, sum = 1;
// Fill last_digits vector with the first 60 sums last digits
for (int i = 2; i < 60; i++) {
temp = a+b;
a = b;
b = temp;
sum += temp;
last_digits[i] = sum%10;
}
// Now return n%60'th element
return last_digits[n%60];
}
int main(int argc, char const *argv[]) {
int n;
std::cin>>n;
std::cout << get_last_digit(n);
return 0;
}
A neat way to solve the problem (I use java). The logic is to utilize the pisano period of 10. To write down the corresponding relationship between Sum(F(n)) = F(n+2) + 1 can help a lot. tip: create a fibonacci sequence alone.
private static long getFibonacciSum(long n) {
n = (n + 2) % 60;
long[] fib = new long[(int) n + 1];
long cor;
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i <= n; i++) {
fib[i] = (fib[i - 1] + fib[i - 2]) % 10;
}
if (fib[(int) n] == 0) cor = 9;
else cor = fib[(int) n] - 1;
return cor;
}

Mixing two arrays by alternating elements two by two

What is an elegant algorithm to mix the elements two by two in two arrays (of potentially differing sizes) so that the items are drawn in an alternating fashion from each array, with the leftovers added to the end?
E.g.
Array 1: 0, 2, 4, 6
Array 2: 1, 3, 5, 7
Mixed array: 0, 2, 1, 3, 4, 6, 5, 7
Don't worry about null checking or any other edge cases, I'll handle those.
Here is my solution but it does not work properly:
for (i = 0; i < N; i++) {
arr[2 * i + 0] = A[i];
arr[2 * i + 1] = A[i+1];
arr[2 * i + 0] = B[i];
arr[2 * i + 1] = B[i+1];
}
It is very fiddly to calculate the array indices explicitly, especially if your arrays can be of different and possibly odd lengths. It is easier if you keep three separate indices, one for each array:
int pairwise(int c[], const int a[], size_t alen, const int b[], size_t blen)
{
size_t i = 0; // index into a
size_t j = 0; // index into b
size_t k = 0; // index into c
while (i < alen || j < blen) {
if (i < alen) c[k++] = a[i++];
if (i < alen) c[k++] = a[i++];
if (j < blen) c[k++] = b[j++];
if (j < blen) c[k++] = b[j++];
}
return k;
}
The returned value k will be equal to alen + blen, which is the implicit dimension of the result array c. Because the availability of a next item is checked for each array operation, this code works for arrays of different lengths and when the arrays have an odd number of elements.
You can use the code like this:
#define countof(x) (sizeof(x) / sizeof(*x))
int main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int b[] = {-1, -2, -3, -4, -5, -6};
int c[countof(a) + countof(b)];
int i, n;
n = pairwise(c, a, countof(a), b, countof(b));
for (i = 0; i < n; i++) {
if (i) printf(", ");
printf("%d", c[i]);
}
puts("");
return 0;
}
(The example is in C, not C++, but your code doesn't use any of C++'s containers such as vector, so I've uses plain old ´int` arrays with explicit dimensions, which are the same in C and C++.)
Some notes on the loop you have;
You use the same position in the result array arr to assign two values to it (one from A and one from B).
The calculation for the index is possibly more complex than it needs to be, consider using two indexers given the two ways you are indexing over the arrays.
I would propose you use a loop that has two indexers (i and j) and explicitly loop over the four elements of the result (i.e. two position for each input array). In each loop you increment the indexers appropriately (by 4 for the output array and by 2 for the input arrays).
#include <iostream>
int main()
{
using namespace std;
constexpr int N = 4;
int A[N] = {2, 4, 6, 8};
int B[N] = {1, 3, 5, 7};
int arr[N*2];
for (auto i = 0, j=0; i < N*2; i+=4, j+=2) {
arr[i + 0] = A[j];
arr[i + 1] = A[j+1];
arr[i + 2] = B[j];
arr[i + 3] = B[j+1];
}
for (auto i =0; i < N*2; ++i) {
cout << arr[i] << ",";
}
cout << endl;
}
Note: you mention you take care of corner cases, so the code here requires the input arrays to be of the same length and that the length is even.
Try this:
for (i = 0; i < N; i += 2) {
arr[2 * i + 0] = A[i];
arr[2 * i + 1] = A[i+1];
arr[2 * i + 2] = B[i];
arr[2 * i + 3] = B[i+1];
}
Didn't consider any corner case, just fixing your concept. For example, check whether any array index out of bound occurs or not. You can run live here.
it should like this.
for (i = 0; i < N; i+=2) {
arr[2 * i + 0] = A[i];
arr[2 * i + 1] = A[i+1];
arr[2 * i + 2] = B[i];
arr[2 * i + 3] = B[i+1];
}

C/C++ - efficient method of rotating an array without using build-in functions (homework)

The task is to rotate left or rotate right a subarray of an array given number of times.
Let me explain this on an example:
lets data be an array.
data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
a sub array is determined by parameters begin and end.
if begin = 3 and end = 7, then subarray is {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
if begin = 7 and end = 3, then subarray is {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
let's rotate it right two times
if begin = 3 and end = 7, then the result is {0, 1, 2, 6, 7, 3, 4, 5, 8, 9};
if begin = 7 and end = 3, then the result is {8, 9, 0, 1,, 4, 5, 6, 2, 3, 7};
I've written code that performs this task but it's to slow.
Can someone give me a hint how to make it quicker?
Important: I'm not allowed to use other arrays than data, subprograms and build-in functions.
#include <iostream>
using namespace std;
int main(){
int dataLength;
cin >> dataLength;
int data [ dataLength ];
for (int i = 0; i < dataLength; i++){
cin >> data [ i ];
}
int begin;
int end;
int rotation;
int forLoopLength;
int tempBefore;
int tempAfter;
cin >> begin;
cin >> end;
cin >> rotation;
if (end > begin)
forLoopLength = (end - begin) + 1;
else
forLoopLength = (end - begin) + 1 + dataLength;
if (rotation < 0)
rotation = forLoopLength + (rotation % forLoopLength);
else
rotation = rotation % forLoopLength;
for (int i = 0; i < rotation; i++) {
tempBefore = data [ end ];
for (int i = 0; i < forLoopLength; i++) {
tempAfter = data [ (begin + i) % dataLength ];
data [ (begin + i) % dataLength ] = tempBefore;
tempBefore = tempAfter;
}
}
for (int i = 0; i < dataLength; i ++ ) {
cout << data [ i ] << " ";
}
return 0;
}
There's a trick to this. It's pretty weird that you'd get this for homework if the trick wasn't mentioned in class. Anyway...
To rotate a sequence of N elements left by M:
reverse the whole sequence
reverse the last M elements
reverse the first N-M elements
done
e.g. left by 2:
1234567
->
7654321
->
7654312
->
3456712
Here is my code, it makes exactly n reads and n writes, where n is subarray size.
#include<iostream>
int arr[]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// replacing 'addr( pos, from, size )' with just 'pos' mean rotation the whole array
int addr( int ptr, int from, int size)
{
return (ptr + from ) % size;
}
void rotate( int* arr, int shift, int from, int count, int size)
{
int i;
int pos= 0;
int cycle= 0;
int c= 0;
int c_old= 0;
// exactly count steps
for ( i=0; i< count; i++ ){
// rotation of arrays part is essentially a permutation.
// every permutation can be decomposed on cycles
// here cycle processing begins
c= arr[ addr( pos, from, size ) ];
while (1){
// one step inside the cycle
pos= (pos + shift) % count;
if ( pos == cycle )
break;
c_old= c;
c= arr[ addr( pos, from, size ) ];
arr[ addr( pos, from, size ) ]= c_old;
i++;
}
// here cycle processing ends
arr[ addr( pos, from, size ) ]= c;
pos= (pos + 1) % count;
cycle= (cycle + 1) % count;
}
}
int main()
{
rotate( arr, 4, 6, 6, 11 );
int i;
for ( i=0; i<11; i++){
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}