Make all elements of the array equal under given conditions - c++

Given an array of size n. Each element denotes the work assigned to some student. Taking some amount of work from a student and assigning it some other student will increase it by a factor of k.
Now we have to redistribute the work such that each student will do equal work. Determine minimum possible work value. And round it off to two decimal places.
A={2,8} K= 1.5 You can take 2.4 from 8 and give it to 2. A={ 2+2.4*1.5 , 8-2.4} Answer is 5.60.
How can we approach to this question. For n=2, I am able to do this simply by solving equations. But for n>2, how can we approach to this. I tried binary search. But I am getting Time limit Exceeded.
sort(a.begin(),a.end());
double low=a[0];
double high= a[n-1];
double res=INT_MAX;
double mid;
int i,j;
while(low<=high){
mid=(low+high)/(2.0);
i=0, j=n-1;
while(i<=j){
if((a[i]+k*a[j])==(k+1)*mid){
i++;
j--;
}
else if((a[i]+k*a[j])<(k+1)*mid){
high=mid;
break;
}
else{
low=mid;
break;
}
}
if(i>j){
res=mid;
high=mid;
}
}
return res;
Please give me suggestions how I can overcome with Time limit exceeded.

If I'm understanding correctly you have an array of doubles and you want to make all elements the same but, the condition is when you subtract you subtract normal but when you add you add multiplied by 1.5, it's basically calculating the average with a condition, so you want make an average and see if its close enough or not so, I made new variable difference that see if the average that we used is bigger or less than the real one, note that difference not give any real value just positive or negative
sort(a.begin(), a.end());
double low = a[0];
double high = a[n - 1];
double average, difference= 0;
average = (low + high) / 2;
do
{
if (difference > 0)
{
low = average;
average = average + high / 2;
}
else if (difference<0)
{
high = average;
average = average + low / 2;
}
for (int i = 0, difference = 0; i < n; i++)
if (a[i] < average)
difference = difference + (a[i]-average) * 1.5;
else
difference = difference + a[i] - average;
} while (difference > 0.01 || difference < -0.01);
The while will done when difference is under 0.01 that's mean average is closer than 0.01 (you can say its 0.01/n almost).
I hope I answered your question, it's my first time to answer question here.

I'd start with some math.
If you graph the values, and you found the target value X, then you would have valleys below X and mountains above X. The volume of the mountains above X, times k, must equal the volume of the valleys.
If you sort the elements, then calculating the net mountain-valley volumes is a linear process. Starting at a_0, all there is is mountain; this is a function of the sum of the a_is and k.
Going from a_i to a_{i+1} makes the a_0 to a_i valleys deeper by a_{i+1}-a_i, and makes the a_{i+1} to a_{last} mountains shallower by the same amount.
In that region the valley/mountain transformation is linear, if it is within that region you can do linear math to find the zero.
Walk from least to greatest, and find the point where the valleys match the mountains.

Related

How to calculate the minimum cost to convert all n numbers in an array to m?

I have been given the following assignment:
Given N integers in the form of A(i) where 1≤i≤N, make each number
A(i) in the N numbers equal to M. To convert a number A(i) to M, it
will cost |M−Ai| units. Find out the minimum cost to convert all the N
numbers to M, so you should choose the best M to get the minimum cost.
Given:
1 <= N <= 10^5
1 <= A(i) <= 10^9
My approach was to calculate the sum of all numbers and find avg = sum / n and then subtract each number by avg to get the minimum cost.
But this fails in many test cases. How can I find the optimal solution for this?
You should take the median of the numbers (or either of the two numbers nearest the middle if the list has even length), not the mean.
An example where the mean fails to minimize is: [1, 2, 3, 4, 100]. The mean is 110 / 5 = 22, and the total cost is 21 + 20 + 19 + 18 + 78 = 156. Choosing the median (3) gives total cost: 2 + 1 + 0 + 1 + 97 = 101.
An example where the median lies between two items in the list is [1, 2, 3, 4, 5, 100]. Here the median is 3.5, and it's ok to either use M=3 or M=4. For M=3, the total cost is 2 + 1 + 0 + 1 + 2 + 97 = 103. For M=4, the total cost is 3 + 2 + 1 + 0 + 1 + 96 = 103.
A formal proof of correctness can be found on Mathematics SE, although you may convince yourself of the result by noting that if you nudge M a small amount delta in one direction (but not past one of the data points) -- and for example's sake let's say it's in the positive direction, the total cost increases by delta times the number of points to the left of M minus delta times the number of points to the right of M. So M is minimized when the number of points to its left and the right are equal in number, otherwise you could move it a small amount one way or the other to decrease the total cost.
#PaulHankin already provided a perfect answer. Anyway, when thinking about the problem, I didn't think of the median being the solution. But even if you don't know about the median, you can come up with a programming solution.
I made similar observations as #PaulHankin in the last paragraph of his last answer. This made me realize, that I have to eliminate outliers iteratively in order to find m. So I wrote a program that first sorts the input array (vector) A and then analyzes the minimum and maximum values.
The idea is to move the minimum values towards the second smallest values and the maximum values towards the second largest values. You always move either the minimum or maximum values, depending on whether you have less minimum values than maximum values or not. If all array items end up being the same value, then you found your m:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int getMinCount(vector<int>& A);
int getMaxCount(vector<int>& A);
int main()
{
// Example as given by #PaulHankin
vector<int> A;
A.push_back(1);
A.push_back(2);
A.push_back(3);
A.push_back(4);
A.push_back(100);
sort(A.begin(), A.end());
int minCount = getMinCount(A);
int maxCount = getMaxCount(A);
while (minCount != A.size() && maxCount != A.size())
{
if(minCount <= maxCount)
{
for(int i = 0; i < minCount; i++)
A[i] = A[minCount];
// Recalculate the count of the minium value, because we changed the minimum.
minCount = getMinCount(A);
}
else
{
for(int i = 0; i < maxCount; i++)
A[A.size() - 1 - i] = A[A.size() - 1 - maxCount];
// Recalculate the count of the maximum value, because we changed the maximum.
maxCount = getMaxCount(A);
}
}
// Print out the one and only remaining value, which is m.
cout << A[0] << endl;
return 0;
}
int getMinCount(vector<int>& A)
{
// Count how often the minimum value exists.
int minCount = 1;
int pos = 1;
while (pos < A.size() && A[pos++] == A[0])
minCount++;
return minCount;
}
int getMaxCount(vector<int>& A)
{
// Count how often the maximum value exists.
int maxCount = 1;
int pos = A.size() - 2;
while (pos >= 0 && A[pos--] == A[A.size() - 1])
maxCount++;
return maxCount;
}
If you think about the algorithm, then you will come to the conclusion, that it actually calculates the median of the values in the array A. As example input I took the first example given by #PaulHankin. As expected, the code provides the correct result (3) for it.
I hope my approach helps you to understand how to tackle such kind of problems even if you don't know the correct solution. This is especially helpful when you are in an interview, for example.

#inf c++ visual studio

I came across question in calculating the sum of a double. When I set iteration to 100000, the function Asian_call_MC still return a number. However, when I set iteration to around 500000 and above, it begin to return 1.#INF. Can someone tell me why it happens and how to solve it? I am using visual studio 2013 to write c++ code.
double Avg_Price(double init_p, double impl_vol, double drift, int step, double deltasqrt)
{
//Calculate the average price of one sample path
//delta = T/ step
//drift = (risk_free - div_y - impl_vol*impl_vol / 2)*(T / step)
double Sa = 0.0;
double St = init_p;
for (int i = 0; i < step; i++)
{
St = St*exp(drift + impl_vol*deltasqrt*normal_gen());
//Sa = Sa * i / (i + 1) + St / (i + 1);
Sa += St;
}
Sa = Sa / double(step);
return Sa;
}
double Asian_call_MC(double strike_p, double T, double init_p, double impl_vol, double risk_free, double div_y, int iter, int step)
{
//Calculate constants in advance to reduce computation time
double drift = (risk_free - div_y - impl_vol*impl_vol / 2)*double(T / step);
double deltasqrt = sqrt(double(T / step));
//Generate x1, average x and y
double cur_p = Avg_Price(init_p,impl_vol,drift,step,deltasqrt);
double pay_o=0.0;
double x = max(cur_p - strike_p,0.0);
//double y = pow(x, 2.0);
//Generate x2 to xn
for (int i = 0; i < iter; i++)
{
cur_p = Avg_Price(init_p, impl_vol, drift, step, deltasqrt);
x = max(cur_p - strike_p,0.0);
//double q = double(i) / double(i + 1);
//pay_o = pay_o *i/(i+1) + x / (i + 1);
pay_o += x;
//y = (1 - (1 / (i + 1)))*y + x*x / (i + 1);
}
//pay_o = pay_o / double(iter);
//stdev = sqrt((y - pow(pay_o , 2)) / (iter - 1));
//return pay_o*exp(-risk_free*T) ;
return pay_o;
}
When you ane increasing the number of iterations, you are increasing the value of the sum. At some point, the value overflows what is possible to contain within a double, thus returning the 1.#INF value that represents infinity as what you calculated. It does this because the calculated value is greater than what can be held in a couple.
To fix the problem, you'll need to change the variable that you're holding the sum with to something that can hold a greater number than a double. The starting point would be using a long double.
Another option would be to build in some of the logic that you have after the for loop into it so you're dealing with smaller numbers. How to do this will vary depending on what exactly you're string to calculate.
It looks like you want to compute mean values. The the way most people learn to calculate a mean is to sum up all the values, then divide the sum by the number of values which contributed to the sum.
This method has a few problems associated with it -- for example, adding many values together might give a sum which is too large for the variable holding it.
Another technique is often used, which accumulates a "running" mean instead of a sum. The running mean's value is always the mean value for all samples already accumulated, so it never blows up into an overflow (floating-point infinity) value (except when one of the accumulated samples was infinity).
The example below demonstrates how to calculate a running mean. It also calculates the sum and shows how sum/count compares to the running mean (to show that they are the same -- I haven't let it run long enough to overflow the sum).
The example uses the C-Library rand(), for demonstration purposes -- I just needed something to calculate mean values from.
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iomanip>
int main() {
srand(static_cast<unsigned>(time(0)));
double count = 0;
double running_mean = 0;
double sum = 0;
auto start = time(0);
auto end = start + 5;
while(time(0) < end) {
double sample = rand();
count += 1;
running_mean += (sample - running_mean)/count;
sum += sample;
}
std::cout << std::setprecision(12);
std::cout << "running mean:" << running_mean << " count:" << count << '\n';
double sum_mean = sum / count;
std::cout << "sum:" << sum << " sum/count:" << sum_mean << '\n';
}
Edit: He already tried this --
the technique appeared in commented-out lines that I missed in the OP's code
Unlike computing the average value by accumulating a grand sum, the running mean technique cannot simply overflow at some point. So knowing that he already tried this and that it didn't help the problem, the probable cause becomes that one of the iteration's terms is, itself INF. As soon as a single INF term is added, the accumulated sum or mean will become INF and stay INF.
The most likely section of code was normal_gen() used inside the argument for a call to the exp function. The name normal_gen() sounds like a source of Normally-distributed random values. The usual implementation employs a Box–Muller transform, which cannot produce values over about 7 standard-deviations away from the mean. So if a Box-Muller generator was causing the INF, it would probably occur within fewer iterations than reported. However, more advanced generators can produce more extreme values -- ideally a Normal distribution has a nonzero probability of producing any finite real value.
If a randomly large Normal sample is what was causing the problem, its correlation with increased iteration count would not be that more iterations inflate the sum, to the point of overflowing by adding more values -- it would be that more iterations gave the program a better chance to hit an unlikely random value which would result in an INF term.
You're overflowing what double can hold. INF is short for infinity, which is the error code you get when you overflow a floating point.
Long double may or may not help depending on your compiler. In Microsoft C++ I believe long double and double are both 64 bits, so no luck there.
Check out Boost multiprecision library, it has larger types, if you really need something that big and can't redo your math. I see you're multiplying a bunch and then dividing. Can you multiply some, then divide, then multiply some more possibly to save space?

Oscilloscope algorithm, dynamic data input, limit output data

I'm trying to make a simple filter incoming data (save maximum and minimum pick), for example: 44100 comes samples per second, but the screen must be displayed 1000. I choose a maximum or minimum in the range of 44.1 samples, and output the screen. However, this algorithm is not very accurate. In the code, it looks like this:
example pseudo algorithm
float max = 0;
float min = 0;
float filter = 0;
float step = 44100/1000;
for(int i = 0 ; i < 44100; i++){
if(input[i] > 0)
if(max < input[i])
max = input[i];
if(input[i] < 0)
if(min > input[i])
min = input[i];
filter++;
if(filter >= step){
filter = filter - step;
//1st version (bad version)
memory[count] = max + min;
//2nd version (bad version)
if(max > abs(min))
memory[count] = max;
else if(max < abs(min))
memory[count] = min;
//3nd version (only maximum)
memory[count] = max; //work great, but only > 0
//4nd version (only minimum)
memory[count] = min; //work great, but only < 0
max = 0;
min = 0;
count++;
if(count >= 1000)
count = 0;
};
};
What am I doing wrong? Separately, everything works fine (max or min), but when connecting all together, result bad.
I have picture, but I can not paste them here.
Links to pictures under this post.
To properly compute the min/max of a set of numbers you have to initialize the values correctly. By setting them to 0 you run into the problems you've found. You have basically two ways to initialize min/max:
Set them to a value larger/smaller than any of your input data.
Set them to the first value in the array.
For (1), if you know your data is, for example, always between -100 and +100 you can simply do:
min = 101;
max = -101;
Note that this doesn't work if your inputs can be any value in the range of the type. For (2) you can do something like:
float max = input[0];
float min = input[0];
...
for (int i ... )
{
...
if (filter >= step)
{
...
min = input[i + 1]; // Be aware of overflow on the last element if
max = input[i + 1]; // input[] is exactly 44100 elements in size
}
}
What do you actually want to see? If it is audio sample, zero means quiet, you probably want to see the envelope - store minimum and maximum for each bin (your bin here=1000 counts) together and display the two in the same picture.
Your sample rate (after division) is 44 Hz, so you can forget some nice simplified waveform (if it is audio)...
The problem that you're seeing in the third graph is that you are storing either a minimum (about -1) or a maximum (about +1). And it's pretty random which of the two you store.
When you then connect the dots, you see a short line segment (2 pixels) whenever you stored two minima or two maxima. But if you store a minimum followed by a maximum, connecting the two gives you a line with a very steep upwards slope. A maximum followed by a minimum gives you a strong downward slope.
The real problem here is that you probably don't realize what you wanted to draw. You should have two arrays, memory_min[] and memory_max[]. And don't mix those two.

C++ program which calculates ln for a given variable x without using any ready functions

I've searched for the equation which calculates the ln of a number x and found out that this equation is:
and I've written this code to implement it:
double ln = x-1 ;
for(int i=2;i<=5;i++)
{
double tmp = 1 ;
for(int j=1;j<=i;j++)
tmp *= (x-1) ;
if(i%2==0)
ln -= (tmp/i) ;
else
ln += (tmp/i) ;
}
cout << "ln: " << setprecision(10) << ln << endl ;
but unfortunately I'm getting outputs completely different from output on my calculator especially for large numbers, can anyone tell me where is the problem ?
The equation you link to is an infinite series as implied by the ellipsis following the main part of the equation and as indicated more explicitly by the previous formulation on the same page:
In your case, you are only computing the first four terms. Later terms will add small refinements to the result to come closer to the actual value, but ultimately to compute all infinite steps will require infinite time.
However, what you can do is approximate your response to something like:
double ln(double x) {
// validate 0 < x < 2
double threshold = 1e-5; // set this to whatever threshold you want
double base = x-1; // Base of the numerator; exponent will be explicit
int den = 1; // Denominator of the nth term
int sign = 1; // Used to swap the sign of each term
double term = base; // First term
double prev = 0; // Previous sum
double result = term; // Kick it off
while (fabs(prev - result) > threshold) {
den++;
sign *=- 1;
term *= base;
prev = result;
result += sign * term / den;
}
return result;
}
Caution: I haven't actually tested this so it may need some tweaking.
What this does is compute each term until the absolute difference between two consecutive terms is less than some threshold you establish.
Now this is not a particularly efficient way to do this. It's better to work with the functions the language you're using (in this case C++) provides to compute the natural log (which another poster has, I believe already shown to you). But there may be some value in trying this for yourself to see how it works.
Also, as barak manos notes below, this Taylor series only converges on the range (0, 2), so you will need to validate the value of x lies in that range before trying to run actual computation.
I believe the natural log in C++ language is simply log
It wouldn't hurt to use long and long double instead of int and double. This may get a little more accuracy on some larger values. Also, your series only extending 5 levels deep is also limiting your accuracy.
Using a series like this is basically an approximation of the logarithmic answer.
This version should be somewhat faster:
double const scale = 1.5390959186233239e-16;
double const offset = -709.05401552996614;
double fast_ln(double x)
{
uint64_t xbits;
memcpy(&xbits, &x, 8);
// if memcpy not allowed, use
// for( i = 0; i < 8; ++i ) i[(char*)xbits] = i[(char*)x];
return xbits * scale + offset;
}
The trick is that this uses a 64-bit integer * 64-bit floating-point multiply, which involves a conversion of the integer to floating-point. Said floating-point representation is similar to scientific notation and requires a logarithm to find the appropriate exponent... but it is done purely in hardware and is very fast.
However it is doing a linear approximation within each octave, which is not very accurate. Using a lookup table for those bits would be far better.
That formula won't work for large inputs, because it would require you to take in consideration the highest degree member, which you can't because they are infinity many.
It will only work for small inputs, where only the first terms of your series are relevant.
You can find ways to do that here: http://en.wikipedia.or/wiki/Pollard%27s_rho_algorithm_for_logarithms
and here: http://www.netlib.org/cephes/qlibdoc.html#qlog
This should work. You just needed the part where if x>=2 shrink x by half and add 0.6931. The reason for 0.6931 is that is ln(2). If you wanted to you could add if (x >= 1024) return myLN(x/1024) + 6.9315 where 6.9315 is ln(1024). This will add speed for big values of x. The for loop with 100 could be much less like 20. I believe to get exact result for an integer its 17.
double myLN(double x) {
if (x >= 2) {
return myLN(x/2.0) + 0.6931;
}
x = x-1;
double total = 0.0;
double xToTheIPower = x;
for (unsigned i = 1; i < 100; i++) {
if (i%2 == 1) {
total += xToTheIPower / (i);
} else {
total -= xToTheIPower / (i);
}
xToTheIPower *= x;
}
return total;
}

Error when Calculating the Approximate Value of e^x [duplicate]

This question already has answers here:
Calculating e^x without using any functions
(4 answers)
Closed 8 years ago.
I am fairly new to c++ and writing a program to calculate the approximate value of e^x. Given by the formula:
1 + X + X^2/2! + ... + X^n/n! (for values of n from 1-100)
The program calculates the value perfectly until the user enters a number for "xValue" larger than 60 (ie. 61 or greater). I am unsure why this is and would really appreciate some feedback:
void calculate_sum(CalculateEx& numberSum)
{
double factoralSum;
numberSum.xTotal = numberSum.xValue;
numberSum.xTotal++;
for (double counter = 2; counter <= 100; counter++)
{
factoralSum = 1;
for (double factoral = 1; factoral <= counter; factoral++)
{
factoralSum *= factoral;
}
numberSum.xNextValue = pow(numberSum.xValue, counter) / factoralSum;
numberSum.xTotal += numberSum.xNextValue;
}
return;
}
Don't calculate the next row element from scratch, store the previous one, x^(n+1)/(n+1)! == (x^n)/n! * x/(n+1). This way you won't have to store values of x^n and especially n! separately (they are simply too big to fit in any reasonable type), whereas the values of x^n/n! converge to 0 as n rises.
Doing something like this would do:
double prevValue = 1;
sum = prevValue;
for (size_t power = 1; power < limit; ++power) {
prevValue *= x / (n + 1);
sum += prevValue;
}
Even a double can only fit so many digits. The computer always has a limit.
I know nothing about scientific computing, but I suppose if you wanted greater precision you might have to find a quad-precision floating point number or something.
Your program is attempting to calculate numbers that are out of the range of normal doubles. You can verify this by printing the value of factoralSum after the loop in which it is computed. If you insist on using the Taylor expansion, you may want to check the value of DBL_MAX in <float.h>
Java has a class called BigDecimal, which lets you create numbers with arbitrarily large precision. In C++, you may want to reference this question: Is there a C++ equivalent to Java's BigDecimal?