Exhaustive (brute force) algorithm improvement - c++

I started with the requirements below:
m,n are integers. Search(x,y,z) with
x+y+z=n
x^3 + y^3 + z^3 = m
And my code
for(int x = 1; x<n; x++)
{
for(int y = 1; y<n; y++)
{
for(int z=1; z<n; z++)
{
if((x*x*x + y*y*y + z*z+z*z == m) &&(x+y+z==n))
{
cout<<x<<" "<<y<<" "<<z;
}
}
}
}
And BigO = n^3
With the block code above, the algorithm is very slow. Have you any idea how to boost speed?

There's no need for the inner loop; given x and y, you can take z = n-x-y. This reduces it to O(n^2).
The second loop only needs to loop while x+y<n, since beyond that there's no positive z such that x+y+z==n. This halves the remaining work.
Once you've done this, there's no need for the second test (since you've already chosen z to make that true); fix the typo in the first test and you get
for (int x = 1; x<n; x++) {
for (int y = 1; x+y<n; y++) {
int z = n-x-y;
if (x*x*x + y*y*y + z*z*z == m) {
// found it
}
}
}

You do not need the internal for z loop. Once you have x and y, you can easily determine z as n-x-y. This makes it O(N^2).
UPD: I think you can even make in O(N log N) using binary search approach.
Iterate over x. For a given x, you need to find such y and z that y+z=n-x and y^3+z^3=m-x^3. Assume n'=n-z and m'=m-x^3.
The problem is symmetric with respect to y and z, so we can safely assume y<=z. This makes y<=n'/2.
We need to find such y that y^3+(n'-y)^3=m'. I am almost sure (though not checked this) that the function f(y)=y^3+(n'-y)^3 is monotonic on the [1, n'/2] interval, so you can use binary search to find the root for f(y)=m' equation.
So, for a given x you can find needed y in O(log N) time, which makes O(N log N) running time in total.

This one is O(n^2)
for(int x = 1; x<n; x++)
{
int n1 = n - x ;
for(int y = 1; y<n1; y++)
{
int z = n - x - y ;
if (x*x*x + y*y*y+z*z*z==m)
{
cout<<x<<" "<<y<<" "<<z;
}
}
}

Related

How to sum two lists correctly?

My task is to form a list Z by summing the elements of two lists.
If it is simpler, then I have two lists X {x1, x2, ... xn} & Y {y1, y2, ..yn} - >> I need to form Z.
X & Y size is the same.
Zi = Xi + Yi
I solve this problem, but I can’t. How can I solve the problem?
Code:
void IndividualTask(list<float>& lisX, list<float>& lisY) {
list<float> Z;
int i = 0;
list<float>::iterator x = lisX.begin();
list<float>::iterator y = lisY.begin();
for (list<float>::iterator it = lisX.begin(); it != lisX.end(); ++it) {
Z.push_back((x + i) + (y + i));
i++;
}
}
You need to make sure you increment both iterators so you have access to both elements:
std::list<float> IndividualTask(std::list<float>& lisX, std::list<float>& lisY) {
std::list<float> Z;
for (auto x = lisX.begin(), y = lisY.begin(); x != lisX.end() && y != lisY.end(); ++x, ++y) {
Z.push_back(*x + *y);
}
return Z;
}
std::list has no random accesss iterators, which means you can't add an a numeric value to it to advance them by several positions. You can only increment or decrement such an iterator by one at a time.
So the idea is to take two iterators and increment both inside the loop, add the values of both iterators and push the result to Z. Something like this:
void IndividualTask(const list<float>& lisX, const list<float>& lisY) {
list<float> Z;
auto x = lisX.begin();
auto y = lisY.begin();
while(x != lisX.end() && y != lisY.end()) {
Z.push_back(*x + *y);
++x;
++y;
}
}
Research std::accumulate in your favorite C++ reference:
std::list<float> numbers;
//...
const float sum = std::accumulate(numbers.begin(), numbers.end(), 0.0);

C++ get parameters before a for loop or not

What is the best practice in this case:
Should I get variables before running a for loop like this:
void Map::render(int layer, Camera* pCam)
{
int texture_index(m_tilesets[layer]->getTextureIndex());
int tile_width(m_size_of_a_tile.getX());
int tile_height(m_size_of_a_tile.getY());
int camera_x(pCam->getPosition().getX());
int camera_y(pCam->getPosition().getY());
int first_tile_x(pCam->getDrawableArea().getX());
int first_tile_y(pCam->getDrawableArea().getY());
int map_max_x( (640 / 16) + first_tile_x );
int map_max_y( (360 / 16) + first_tile_y );
if (map_max_x > 48) { map_max_x = 48; }
if (map_max_y > 28) { map_max_x = 28; }
Tile* t(nullptr);
for (int y(first_tile_y); y < map_max_y; ++y) {
for (int x(first_tile_x); x < map_max_x; ++x) {
// move map relative to camera
m_dst_rect.x = (x * tile_width) + camera_x;
m_dst_rect.y = (y * tile_height) + camera_y;
t = getTile(layer, x, y);
if (t) {
pTextureManager->draw(texture_index, getTile(layer, x, y)->src, m_dst_rect);
}
}
}
}
or is it better to get it directly in the loop like this (in this case the code is shorter but less readable):
void Map::render(int layer, Camera* pCam)
{
int first_tile_x(pCam->getDrawableArea().getX());
int first_tile_y(pCam->getDrawableArea().getY());
for (int y(first_tile_y); y < (640 / 16) + first_tile_x; ++y) {
for (int x(first_tile_x); x < (360 / 16) + first_tile_y; ++x) {
// move map relative to camera
m_dst_rect.x = (x * m_size_of_a_tile.getX()) + pCam->getPosition().getX();
m_dst_rect.y = (y * m_size_of_a_tile.getY()) + pCam->getPosition().getY();
Tile* t(getTile(layer, x, y));
if (t) {
pTextureManager->draw(m_tilesets[layer]->getTextureIndex(), getTile(layer, x, y)->src, m_dst_rect);
}
}
}
}
Is there an impact on performance using one method over another?
Syntactically the second version is to be preferred as it does contain the object in the scope where it is being used, not leaking it to different contexts. Performance wise you will need to profile but I'd be surprised if there was any difference at all because a compiler will often notice that the results don't change, at least for simple functions, and do this optimization for you.
For functions that are more complex or potentially dynamic, but you know they will not change their result during the for loop it makes sense to define them before the loop.

Calculating 3D cartesian coordinates inside a cone

So what I am essentially trying to do here is arranging the 3D cartesian coordinates of points inside an inverted cone (radius decreases with height). The basic approach I have taken here is to have an integrally reducing height, h, and plotting points (x,y) that fall within a circle formed at height h. Since the radius of this circle is variable, I am using a simple similarity condition to determine that at every iteration. The initial height I have taken is 1000, the radius ought to initially be 3500. Also, these circles as centred at (0,0) [the z-axis passes through the vertex of the cone, and is perpendicular to the base]. Code isn't running properly, showing me an exit status of -1. Can anyone help me figure out if my implementation is off due to some size errors or something?
#include<bits/stdc++.h>
#define ll long long int
using namespace std;
int main(){
float top[1010][9000][3];
ll i = 0;
for(ll h = 999; h >=0; h--){
float r=(h+1)*(3.5);
for (ll x = floor(r) * (-1); x <= floor(r); x++){
for (ll y = floor(r) *(-1); y <= floor(r); y++){
if(pow(x,2) + pow(y,2) <= pow(floor(r),2)){
top[h][i][0] = x;
top[h][i][1] = y;
top[h][i][2] = 9.8;
i++;
}
}
}
i=0;
}
cout << "done";
for (ll m = 0; m < 1000; m++){
for(ll n = 0; n < 7000; n++){
if(top[m][n][2] == 9.8){
cout << top[m][n][0] << top[m][n][1];
}
}
}
}
You don't need to declare ll as long long int. The indexes you are using will fit inside of int.
Here's your problem: Change the code to this to see what's going on:
for(ll h = 999; h >=0; h--){
float r=(h+1)*(3.5);
for (ll x = floor(r) * (-1); x <= floor(r); x++){
for (ll y = floor(r) *(-1); y <= floor(r); y++){
if(pow(x,2) + pow(y,2) <= pow(floor(r),2)){
/* top[h][i][0] = x;
top[h][i][1] = y;
top[h][i][2] = 9.8; //*/
i++; // this gets really big
}
}
}
cout << "max i: " << i << endl;
i=0;
}
i gets really big and is indexing into a dimension that is only 9000.
Criticism of the code...
It looks like you are scanning the entire x,y,z block and 'testing' if the point is inside. If yes, saving the x,y coordinate of the point along with 9.8 (some field value?).
Perhaps you could forgo the float buffer and just print the {x,y} coordinates directly to see how your code works before attempting to save the output. redirect the output to a file and inspect.
cout << "{" << x << "," << y <<"}," << (i % 5 == 0 ? "\n" : " ");
Also, read up on why comparing floats with == doesn't work.

Audio Processing C++ - FFT

I'm probably going to ask this incorrectly and make myself look very stupid but here goes:
I'm trying to do some audio manipulate and processing on a .wav file. Now, I am able to read all of the data (including the header) but need the data to be in frequency, and, in order to this I need to use an FFT.
I searched the internet high and low and found one, and the example was taken out of the "Numerical Recipes in C" book, however, I amended it to use vectors instead of arrays. Ok so here's the problem:
I have been given (as an example to use) a series of numbers and a sampling rate:
X = {50, 206, -100, -65, -50, -6, 100, -135}
Sampling Rate : 8000
Number of Samples: 8
And should therefore answer this:
0Hz A=0 D=1.57079633
1000Hz A=50 D=1.57079633
2000HZ A=100 D=0
3000HZ A=100 D=0
4000HZ A=0 D=3.14159265
The code that I re-wrote compiles, however, when trying to input these numbers into the equation (function) I get a Segmentation fault.. Is there something wrong with my code, or is the sampling rate too high? (The algorithm doesn't segment when using a much, much smaller sampling rate). Here is the code:
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
#define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr;
#define pi 3.14159
void ComplexFFT(vector<float> &realData, vector<float> &actualData, unsigned long sample_num, unsigned int sample_rate, int sign)
{
unsigned long n, mmax, m, j, istep, i;
double wtemp,wr,wpr,wpi,wi,theta,tempr,tempi;
// CHECK TO SEE IF VECTOR IS EMPTY;
actualData.resize(2*sample_rate, 0);
for(n=0; (n < sample_rate); n++)
{
if(n < sample_num)
{
actualData[2*n] = realData[n];
}else{
actualData[2*n] = 0;
actualData[2*n+1] = 0;
}
}
// Binary Inversion
n = sample_rate << 1;
j = 0;
for(i=0; (i< n /2); i+=2)
{
if(j > i)
{
SWAP(actualData[j], actualData[i]);
SWAP(actualData[j+1], actualData[i+1]);
if((j/2)<(n/4))
{
SWAP(actualData[(n-(i+2))], actualData[(n-(j+2))]);
SWAP(actualData[(n-(i+2))+1], actualData[(n-(j+2))+1]);
}
}
m = n >> 1;
while (m >= 2 && j >= m) {
j -= m;
m >>= 1;
}
j += m;
}
mmax=2;
while(n > mmax) {
istep = mmax << 1;
theta = sign * (2*pi/mmax);
wtemp = sin(0.5*theta);
wpr = -2.0*wtemp*wtemp;
wpi = sin(theta);
wr = 1.0;
wi = 0.0;
for(m=1; (m < mmax); m+=2) {
for(i=m; (i <= n); i += istep)
{
j = i*mmax;
tempr = wr*actualData[j-1]-wi*actualData[j];
tempi = wr*actualData[j]+wi*actualData[j-1];
actualData[j-1] = actualData[i-1] - tempr;
actualData[j] = actualData[i]-tempi;
actualData[i-1] += tempr;
actualData[i] += tempi;
}
wr = (wtemp=wr)*wpr-wi*wpi+wr;
wi = wi*wpr+wtemp*wpi+wi;
}
mmax = istep;
}
// determine if the fundamental frequency
int fundemental_frequency = 0;
for(i=2; (i <= sample_rate); i+=2)
{
if((pow(actualData[i], 2)+pow(actualData[i+1], 2)) > pow(actualData[fundemental_frequency], 2)+pow(actualData[fundemental_frequency+1], 2)) {
fundemental_frequency = i;
}
}
}
int main(int argc, char *argv[]) {
vector<float> numbers;
vector<float> realNumbers;
numbers.push_back(50);
numbers.push_back(206);
numbers.push_back(-100);
numbers.push_back(-65);
numbers.push_back(-50);
numbers.push_back(-6);
numbers.push_back(100);
numbers.push_back(-135);
ComplexFFT(numbers, realNumbers, 8, 8000, 0);
for(int i=0; (i < realNumbers.size()); i++)
{
cout << realNumbers[i] << "\n";
}
}
The other thing, (I know this sounds stupid) but I don't really know what is expected of the
"int sign" That is being passed through the ComplexFFT function, this is where I could be going wrong.
Does anyone have any suggestions or solutions to this problem?
Thank you :)
I think the problem lies in errors in how you translated the algorithm.
Did you mean to initialize j to 1 rather than 0?
for(i = 0; (i < n/2); i += 2) should probably be for (i = 1; i < n; i += 2).
Your SWAPs should probably be
SWAP(actualData[j - 1], actualData[i - 1]);
SWAP(actualData[j], actualData[i]);
What are the following SWAPs for? I don't think they're needed.
if((j/2)<(n/4))
{
SWAP(actualData[(n-(i+2))], actualData[(n-(j+2))]);
SWAP(actualData[(n-(i+2))+1], actualData[(n-(j+2))+1]);
}
The j >= m in while (m >= 2 && j >= m) should probably be j > m if you intended to do bit reversal.
In the code implementing the Danielson-Lanczos section, are you sure j = i*mmax; was not supposed to be an addition, i.e. j = i + mmax;?
Apart from that, there are a lot of things you can do to simplify your code.
Using your SWAP macro should be discouraged when you can just use std::swap... I was going to suggest std::swap_ranges, but then I realized you only need to swap the real parts, since your data is all reals (your time-series imaginary parts are all 0):
std::swap(actualData[j - 1], actualData[i - 1]);
You can simplify the entire thing using std::complex, too.
I reckon its down to the re-sizing of your vector.
One possibility: Maybe re-sizing will create temp objects on the stack before moving them back to heap i think.
The FFT in Numerical Recipes in C uses the Cooley-Tukey Algorithm, so in answer to your question at the end, the int sign being passed allows the same routine to be used to compute both the forward (sign=-1) and inverse (sign=1) FFT. This seems to be consistent with the way you are using sign when you define theta = sign * (2*pi/mmax).

How to optimize a for loop?

I have a problem, let's say:
Find all two pairs of numbers (x,y) and (z,t) such that x³ + y³ = z³ + t³, where (x, y) != (z, t) and x³ + y³ < 10,000.
Taking the cube root of 10,000 yeilds 21.544 -> round down to 21, so I got:
#include <iostream>
using namespace std;
int main() {
for( int x = 1; x <= 20; ++x ) {
for( int y = x + 1; y <= 21; ++y ) {
for( int z = x + 1; z <= y - 1; ++z ) {
for( int t = z; t <= y - 1; ++t ) {
if( x*x*x + y*y*y == z*z*z + t*t*t ) {
cout << x << ", " << y << ", " << z << ", " << t << endl;
}
}
}
}
}
return 0;
}
I know this code could be optimized more, and that's what I'm looking for. Plus, one of my friends told me that y could be x + 2 instead of x + 1, and I doubt this since if
x = 1, then we will never have y = 2, which in this case missed one possible solution.
Any thought?
Well there's one obvious algorithmic optimization that can be made given the current loop structure, you optimize quite rightly by limiting your ranges to the cube root of 10,000. However you can go farther and limit your range on y based on the cube root of 10,000 - x. That's one thing you can do.
The other optimization is that there's no reason on earth that this should be 4 loops. Simply do 2 loops and compute the values of x^3 + y^3 and check for duplicates. (This is as good as you're going to get without delving into features of cube roots.)
This isn't actually using the API correctly but you get the idea:
multimap<int, std::pair<int, int> > map;
for (int i = 1; i < 21; i++) {
(for int j = x; j < cube_root(10000 - i^3); j++ {
multimap.insert (i^3 + j^3, std::pair<int, int>(i,j);
Then you just iterate through the multimap and look for repeats.
Typical tradeoff: memory for speed.
First the bound on x is quite large: if we suppose that (x,y) is ordered with x <= y, then
x^3 + y^3 < N and x^3 < y^3 (for positive numbers)
=> x^3 + x^3 < N (by transitivity)
<=> x^3 < N/2
<=> x <= floor((N/2)^(1/3))
Thus x <= 17 here.
Now, let us memoize the result of x^3 + y^3 and build an associative table (sum -> pairs). By the way, is there a reason to discard (x,x) as a pair ?
int main(int argc, char* argv[])
{
typedef std::pair<unsigned short, unsigned short> Pair;
typedef std::vector<Pair> PairsList;
typedef std::unordered_map<unsigned short, PairsList> SumMap;
// Note: arbitrary limitation, N cannot exceed 2^16 on most architectures
// because of the choice of using an `unsigned short`
unsigned short N = 10000;
if (argc > 1) { N = boost::lexical_cast<unsigned short>(argv[1]); }
SumMap sumMap;
for (unsigned short x = 1; x*x*x <= N/2; ++x)
{
for (unsigned short y = x; x*x*x + y*y*y <= N; ++y)
{
sumMap[x*x*x + y*y*y].push_back(Pair(x,y));
}
}
for (SumMap::const_reference ref: sumMap)
{
if (ref.second.size() > 1)
{
std::cout << "Sum: " << ref.first
<< " can be achieved with " << ref.second << "\n";
// I'll let you overload the print operator for a vector of pairs
}
}
return 0;
}
We are O(N^2) here.
Make a list of all numbers and their operational result. Sort the list by the results. Test matching results for having different operands.
Use a table from sums to the set of pairs of numbers generating that sum.
You can generate that table by two nested for loops, and then run through the table collecting the sums with multiple solutions.
I'd suggest calculating the powers in outer loops (EDIT: Moved calculations out of the for loops):
int x3, y3, z3;
for( int x = 1; x <= 20; ++x ) {
x3 = x * x * x;
for( int y = x + 1; y <= 21; ++y ) {
y3 = y * y * y;
for( int z = x + 1; z <= y - 1; ++z ) {
z3 = z * z * z;
for( int t = z; t <= y - 1; ++t ) {
if( x3 + y3 == z3 + t*t*t ) {
cout << x << ", " << y << ", " << z << ", " << t << endl;
}
}
}
}
}
Anyway, why do you want to optimize (at least for this example)? This runs in 20 ms on my PC... So I guess you have similar problems at a larger scale.
As a general summary:
Calculate the cubes as you loop rather than at the end, thus int xcubed = x*x*x; just after the loop of x (similarly with y and z). This saves you calculating the same values multiple times. Put them in a table so you only calculate these once.
Create a table of sums of cubes, using a hash_table of some extent, and let it hold duplicates (not to be confused with a hashed-collision).
Any that has a duplicate is a solution.
1729 should come up as one of your solutions by the way. 1 cubed plus 12 cubed and also 9 cubed + 10 cubed.
To test performance you could of course pick a much higher value of maxsum (as well as run it several times).
The algorithm is strictly O(N^2/3). (2/3 because you go only to the cube-root of N and then it is O(m^2) on that smaller range).