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.
Related
In C++ is there a function to count all the pixels with a certain value inside a given rectangle (xmin, ymin, xmax, ymax), using GDAL library? Or I'll have to read each block and count them all pixel by pixel? I have searched, but only found a few Python scripts that do that.
I did it for myself (it's a boolean raster - 0/1 - and I'm counting the "1" pixels), but the result is different from that given in GRASS GIS r.report function (via QGIS).
long long openTIF(string ftif,double x0,double y0,double x1,double y1) {
long long sum = 0;
GDALDataset *poDataset;
GDALAllRegister();
poDataset = (GDALDataset*)GDALOpen(ftif.c_str(),GA_ReadOnly);
if (poDataset == NULL) {
cout << "Error reading raster '" << ftif << "'\n";
exit(1);
}
int tx=poDataset->GetRasterXSize(),
ty=poDataset->GetRasterYSize();
double geoTransf[6], rx0=0, ry0=0, rx1=0, ry1=0;
if (poDataset->GetGeoTransform(geoTransf) == CE_None) {
rx0 = geoTransf[0];
ry0 = geoTransf[3]-ty*geoTransf[1];
rx1 = geoTransf[0]-tx*geoTransf[5];
ry1 = geoTransf[3];
} else {
exit(2);
}
int nBlockXSize,nBlockYSize;
GDALRasterBand *poBand;
poBand = poDataset->GetRasterBand(1);
poBand->GetBlockSize(&nBlockXSize,&nBlockYSize);
uint32_t i;
int y,
col0 = round((rx0-x0)/geoTransf[5]),
col1 = round((rx0-x1)/geoTransf[5]),
row0 = round((ry1-y1)/geoTransf[1]),
row1 = round((ry1-y0)/geoTransf[1]);
CPLErr error;
uint8_t *data = (uint8_t*)CPLMalloc(nBlockXSize*nBlockYSize);
GDALDataType type = poBand->GetRasterDataType();
if (type == GDT_Byte) {
cout << "Byte" << endl;
}
for (y=row0; y<row1; y++) {
error = poBand->ReadBlock(0,y,data);
if (error > 0) {
cout << "Error reading data block.\n";
exit(3);
}
for (i=col0; i<col1; i++) {
sum += (uint8_t)data[i];
}
}
CPLFree(data);
return sum;
}
For this given raster, and the given coordinates (precision %.8f), GRASS GIS r.report function is reporting 28096011 pixels with value 1, while my sum is giving 28094709 (difference = -1302). With other coordinates r.report gives 5605458, my sum gives 5604757 (difference = -701). Any idea what may be going on?
EDIT: Since my sum was always smaller than GRASS GIS r.report, I though of including the last row and column, changing the lines
for (y=row0; y<row1; y++) {
for (i=col0; i<col1; i++) {
to
for (y=row0; y<=row1; y++) {
for (i=col0; i<=col1; i++) {
but now, with another set of coordinates, r.report gives 249707, while my sum gives 250157 (difference = +450).
It looks like a rounding error, you need to round down your column and row indexes. It's easier to reason if you think about every raster pixel as a rectangular region. For example, first pixel of your raster spans from (x, y) to (x + width, y + height).
rx = geoTransf[0];
rx_size = geoTransf[1]; // you got geoTransf[1] and geoTransf[5] swapped!
ry = geoTransf[3];
ry_size = geoTransf[5];
// assert, that geoTrans[2] and geoTrans[4] are zero
col_first = floor((x0 - rx) / rx_size));
col_last = floor((x1 - rx) / rx_size));
row_first = floor((y0 - ry) / ry_size));
row_last = floor((y1 - ry) / ry_size));
for (int y = row_first; y <= row_last; ++y) {
poBand->ReadBlock(col_first, y, data);
for (int x = 0; x <= col_last - col_first; ++x) {
data[x];
}
}
I am working on escape-time fractals as my 12th grade project, to be written in c++ , using the simple graphics.h library that is outdated but seems sufficient.
The code for generating the Mandelbrot set seems to work, and I assumed that Julia sets would be a variation of the same. Here is the code:
(Here, fx and fy are simply functions to convert the actual complex co-ordinates like (-0.003,0.05) to an actual value of a pixel on the screen.)
int p;
x0=0, y0=0;
long double r, i;
cout<<"Enter c"<<endl;
cin>>r>>i;
for(int i= fx(-2); i<=fx(2); i++)
{
for(int j= fy(-2); j>=fy(2); j--)
{
long double x=0.0, y= 0.0,t;
x= gx(i), y= gy(j);
int k= -1;
while(( x*x + y*y <4)&& k<it-1)
{
t= x*x - y*y + r;
y= 2*x*y + i ;
x=t;
k++;
}
p= k*pd;
setcolor(COLOR(colour[p][0],colour[p][1],colour[p][2]));
putpixel(i,j,getcolor());
}
}
But this does not seem to be the case. The output window shows the entire circle of radius=2 with the colour corresponding to an escape time of 1 iteration.
Also, on trying to search for a solution to this problem, I've seen that all the algorithms others have used initializes the initial co-ordinates somewhat like this:
x = (col - width/2)*4.0/width;
y = (row - height/2)*4.0/width;
Could somebody explain what I'm missing out?
I guess that the main problem is that the variable i (imaginary part) is mistakenly overridden by the loop variable i. So the line
y= 2*x*y + i;
gives the incorrect result. This variable should be renamed as, say im. The corrected version is attached below, Since I don't have graphics.h, I used the screen as the output.
#include <iostream>
using namespace std;
#define WIDTH 40
#define HEIGHT 60
/* real to screen */
#define fx(x) ((int) ((x + 2)/4.0 * WIDTH))
#define fy(y) ((int) ((2 - y)/4.0 * HEIGHT))
/* screen to real */
#define gx(i) ((i)*4.0/WIDTH - 2)
#define gy(j) ((j)*4.0/HEIGHT - 2)
static void julia(int it, int pd)
{
int p;
long double re = -0.75, im = 0;
long double x0 = 0, y0 = 0;
cout << "Enter c" << endl;
cin >> re >> im;
for (int i = fx(-2.0); i <= fx(2.0); i++)
{
for (int j = fy(-2.0); j >= fy(2.0); j--)
{
long double x = gx(i), y = gy(j), t;
int k = 0;
while (x*x + y*y < 4 && k < it)
{
t = x*x - y*y + re;
y = 2*x*y + im;
x = t;
k++;
}
p = (int) (k * pd);
//setcolor(COLOR(colour[p][0],colour[p][1],colour[p][2]));
//putpixel(i,j,getcolor());
cout << p; // for ASCII output
}
cout << endl; // for ASCII output
}
}
int main(void)
{
julia(9, 1);
return 0;
}
and the output with input -0.75 0 is given below.
0000000000000000000000000000000000000000000000000000000000000
0000000000000000000001111111111111111111000000000000000000000
0000000000000000011111111111111111111111111100000000000000000
0000000000000001111111111111111111111111111111000000000000000
0000000000000111111111111122222222211111111111110000000000000
0000000000011111111111122222349432222211111111111100000000000
0000000001111111111112222233479743322222111111111111000000000
0000000011111111111222222334999994332222221111111111100000000
0000000111111111112222223345999995433222222111111111110000000
0000011111111111122222234479999999744322222211111111111100000
0000011111111111222222346899999999986432222221111111111100000
0000111111111111222223359999999999999533222221111111111110000
0001111111111112222233446999999999996443322222111111111111000
0011111111111112222233446999999999996443322222111111111111100
0011111111111122222333456899999999986543332222211111111111100
0111111111111122223334557999999999997554333222211111111111110
0111111111111122233345799999999999999975433322211111111111110
0111111111111122233457999999999999999997543322211111111111110
0111111111111122334469999999999999999999644332211111111111110
0111111111111122345999999999999999999999995432211111111111110
0111111111111122379999999999999999999999999732211111111111110
0111111111111122345999999999999999999999995432211111111111110
0111111111111122334469999999999999999999644332211111111111110
0111111111111122233457999999999999999997543322211111111111110
0111111111111122233345799999999999999975433322211111111111110
0111111111111122223334557999999999997554333222211111111111110
0011111111111122222333456899999999986543332222211111111111100
0011111111111112222233446999999999996443322222111111111111100
0001111111111112222233446999999999996443322222111111111111000
0000111111111111222223359999999999999533222221111111111110000
0000011111111111222222346899999999986432222221111111111100000
0000011111111111122222234479999999744322222211111111111100000
0000000111111111112222223345999995433222222111111111110000000
0000000011111111111222222334999994332222221111111111100000000
0000000001111111111112222233479743322222111111111111000000000
0000000000011111111111122222349432222211111111111100000000000
0000000000000111111111111122222222211111111111110000000000000
0000000000000001111111111111111111111111111111000000000000000
0000000000000000011111111111111111111111111100000000000000000
0000000000000000000001111111111111111111000000000000000000000
0000000000000000000000000000000000000000000000000000000000000
would you please tell how you display the image by using these graphics.h library
//setcolor(COLOR(colour[p][0],colour[p][1],colour[p][2]));
//putpixel(i,j,getcolor());
I have the following code.
Essentially it is creating N random normal variables, and running through an equation M times for a simulation.
The output should be an NxM matrix of data, however the only way I could do the calculation has the output as MxN. ie each M run should be a column, not a row.
I have attempted in vain to follow some of the other suggestions that have been posted on previous similar topics.
Code:
#include <iostream>
#include <time.h>
#include <random>
int main()
{
double T = 1; // End time period for simulation
int N = 4; // Number of time steps
int M = 2; // Number of simulations
double x0 = 1.00; // Starting x value
double mu = 0.00; // mu(x,t) value
double sig = 1.00; // sigma(x,t) value
double dt = T/N;
double sqrt_dt = sqrt(dt);
double** SDE_X = new double*[M]; // SDE Matrix setup
// Random Number generation setup
double RAND_N;
srand ((unsigned int) time(NULL)); // Generator loop reset
std::default_random_engine generator (rand());
std::normal_distribution<double> distribution (0.0,1.0); // Mean = 0.0, Variance = 1.0 ie Normal
for (int i = 0; i < M; i++)
{
SDE_X[i] = new double[N];
for (int j=0; j < N; j++)
{
RAND_N = distribution(generator);
SDE_X[i][0] = x0;
SDE_X[i][j+1] = SDE_X[i][j] + mu * dt + sig * RAND_N * sqrt_dt; // The SDE we wish to plot the path for
std::cout << SDE_X[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
std::cout << " The simulation is complete!!" << std::endl;
std::cout << std::endl;
system("pause");
return 0;
}
Well why can't you just create the transpose of your SDE_X matrix then? Isn't that what you want to get?
Keep in mind, that presentation has nothing to do with implementation. Whether to access columns or rows is your decision. So you want an implementation of it transposed. Then quick and dirty create your matrix first, and then create your number series. Change i and j, and N and M.
I said quick and dirty, because the program at all is bad:
why don't you just keep it simple and use a better data structure for your matrix? If you know the size: compile-time array or dynamic vectors at runtime? Maybe there are some nicer implementation for 2d array.
There is a bug I think: you create N doubles and access index 0 to N inclusive.
In every iteration you set index 0 to x0 what is also needless.
I would change your code a bit make more clear:
create your matrix at first
initialize the first value of the matrix
provide an algorithm function calculating a target cell taking the matrix and the parameters.
Go through each cell and invoke your function for that cell
Thank you all for your input. I was able to implement my code and have it displayed as needed.
I added a second for loop to rearrange the matrix rows and columns.
Please feel free to let me know if you think there is anyway I can improve it.
#include <iostream>
#include <time.h>
#include <random>
#include <vector>
int main()
{
double T = 1; // End time period for simulation
int N = 3; // Number of time steps
int M = 2; // Number of simulations
int X = 100; // Max number of matrix columns
int Y = 100; // Max number of matrix rows
double x0 = 1.00; // Starting x value
double mu = 0.00; // mu(x,t) value
double sig = 1.00; // sigma(x,t) value
double dt = T/N;
double sqrt_dt = sqrt(dt);
std::vector<std::vector<double>> SDE_X((M*N), std::vector<double>((M*N))); // SDE Matrix setup
// Random Number generation setup
double RAND_N;
srand ((unsigned int) time(NULL)); // Generator loop reset
std::default_random_engine generator (rand());
std::normal_distribution<double> distribution (0.0,1.0); // Mean = 0.0, Variance = 1.0 ie Normal
for (int i = 0; i <= M; i++)
{
SDE_X[i][0] = x0;
for (int j=0; j <= N; j++)
{
RAND_N = distribution(generator);
SDE_X[i][j+1] = SDE_X[i][j] + mu * dt + sig * RAND_N * sqrt_dt; // The SDE we wish to plot the path for
}
}
for (int j = 0; j <= N; j++)
{
for (int i = 0; i <=M; i++)
{
std::cout << SDE_X[i][j] << ", ";
}
std::cout << std::endl;
}
std::cout << std::endl;
std::cout << " The simulation is complete!!" << std::endl;
std::cout << std::endl;
system("pause");
return 0;
}
I would like to simulate a point mass within a closed box. There is no friction and the point mass obeys the impact law. So there are only elastic collisions with the walls of the box. The output of the program is the time, position (rx,ry ,rz) and velocity (vx,vy,vz). I plot the trajectory by using GNUplot.
The problem I have now is, that the point mass gets energy from somewhere. So their jumps get each time more intense.
Is someone able to check my code?
/* Start of the code */
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
struct pointmass
{
double m; // mass
double r[3]; // coordinates
double v[3]; // velocity
};
// Grav.constant
const double G[3] = {0, -9.81, 0};
int main()
{
int Time = 0; // Duration
double Dt = 0; // Time steps
pointmass p0;
cerr << "Duration: ";
cin >> Time;
cerr << "Time steps: ";
cin >> Dt;
cerr << "Velocity of the point mass (vx,vy,vz)? ";
cin >> p0.v[0];
cin >> p0.v[1];
cin >> p0.v[2];
cerr << "Initial position of the point mass (x,y,z)? ";
cin >> p0.r[0];
cin >> p0.r[1];
cin >> p0.r[2];
for (double i = 0; i<Time; i+=Dt)
{
cout << i << setw(10);
for (int j = 0; j<=2; j++)
{
////////////position and velocity///////////
p0.r[j] = p0.r[j] + p0.v[j]*i + 0.5*G[j]*i*i;
p0.v[j] = p0.v[j] + G[j]*i;
///////////////////reflection/////////////////
if(p0.r[j] >= 250)
{
p0.r[j] = 500 - p0.r[j];
p0.v[j] = -p0.v[j];
}
else if(p0.r[j] <= 0)
{
p0.r[j] = -p0.r[j];
p0.v[j] = -p0.v[j];
}
//////////////////////////////////////////////
}
/////////////////////Output//////////////////
for(int j = 0; j<=2; j++)
{
cout << p0.r[j] << setw(10);
}
for(int j = 0; j<=2; j++)
{
cout << p0.v[j] << setw(10);
}
///////////////////////////////////////////////
cout << endl;
}
}
F = ma
a = F / m
a dt = F / m dt
a dt is acceleration over a fixed time - the change in velocity for that frame.
You are setting it to F / m i
it is that i which is wrong, as comments have suggested. It needs to be the duration of a frame, not the duration of the entire simulation so far.
I am a little concerned about the time loop along with other commenters - make sure that it represents an increment of time, not a growing duration.
Still, I think the main problem is you are changing the sign of all three components of velocity
on reflection.
That's not consistent with the laws of physics -conservation of linear momentum and energy - at the boundaries.
To see this, consider the case if your particle is moving in just the x-y plane (velocity in z is zero) and about to hit the wall at x= L.
The collision looks like this:
The force exerted on the point mass by the wall acts perpendicular to the wall. So there is no change in the momentum component of the particle parallel to the wall.
Applying conservation of linear momentum and kinetic energy, and assuming a perfectly elastic collision, you will find that
The component of velocity perpendicular to the wall DOES change sign
The component of velocity parallel to the wall DOES NOT change sign
In three dimensions, to have an accurate simulation, you have to work out the momentum components parallel and perpendicular to the wall on collision and code the resulting velocity changes.
In other words, this code:
///////////////////reflection/////////////////
if(p0.r[j] >= 250)
{
p0.r[j] = 500 - p0.r[j];
p0.v[j] = -p0.v[j];
}
else if(p0.r[j] <= 0)
{
p0.r[j] = -p0.r[j];
p0.v[j] = -p0.v[j];
}
//////////////////////////////////////////////
does not model the physics of reflection correctly. To fix it here is an outline of what to do:
Take the reflection checks out of the loop over x,y,z coordinates (but still within the time loop)
The collision condition for all six walls needs to be checked,
according to the direction of the normal vector to the wall.
For example for the right wall of the cube defined by X=250, 0<=Y<250, 0<=Z<250, the normal vector is in the negative X direction. For the left wall defined by X=0, 0<=Y<250, 0<=Z<250, the normal vector is in the positive X direction.
So on reflection from those two walls, the X component of velocity changes sign because it is normal (perpendicular) to the wall, but the Y and Z components do NOT change sign because they are parallel to the wall.
Apply similar considerations at the top and bottom wall (constant Y), and front and back wall (constant Z), of the cube -left as exercise to work out the normals to those surfaces.
Finally you shouldn't change sign of the position vector components on reflection, just the velocity vector. Instead recompute the next value of the position vector given the new velocity.
OK, so there are a few issues. The others have pointed out the need to use Dt rather than i for the integration step.
However, you are correct in stating that there is an issue with the reflection and energy conservation. I've added an explicit track of that below.
Note that the component wise computation of the reflection is actually fine other than the energy issue.
The problem was that during a reflection the acceleration due to gravity changes. In the case of the particle hitting the floor, it was acquiring kinetic energy equal to that it would have had if it had kept falling, but the new position had higher potential energy. So the energy would increase by exactly twice the potential energy difference between the floor and the new position. A bounce off the roof would have the opposite effect.
As noted below, once strategy would be to compute the actual time of reflection. However, actually working directly with energy is much simpler as well as more robust. However, please note although the the simple energy version below ensures that the speed and position are consistent, it actually does not have the correct position. For most purposes that may not actually matter. If you really need the correct position, I think we need to solve for the bounce time.
/* Start of the code */
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
struct pointmass
{
double m; // mass
double r[3]; // coordinates
double v[3]; // velocity
};
// Grav.constant
const double G[3] = { 0, -9.81, 0 };
int main()
{
// I've just changed the initial values to speed up unit testing; your code worked fine here.
int Time = 50; // Duration
double Dt = 1; // Time steps
pointmass p0;
p0.v[0] = 23;
p0.v[1] = 40;
p0.v[2] = 15;
p0.r[0] = 100;
p0.r[1] = 200;
p0.r[2] = 67;
for (double i = 0; i<Time; i += Dt)
{
cout << setw(10) << i << setw(10);
double energy = 0;
for (int j = 0; j <= 2; j++)
{
double oldR = p0.r[j];
double oldV = p0.v[j];
////////////position and velocity///////////
p0.r[j] = p0.r[j] + p0.v[j] * Dt + 0.5*G[j] * Dt*Dt;
p0.v[j] = p0.v[j] + G[j] * Dt;
///////////////////reflection/////////////////
if (G[j] == 0)
{
if (p0.r[j] >= 250)
{
p0.r[j] = 500 - p0.r[j];
p0.v[j] = -p0.v[j];
}
else if (p0.r[j] <= 0)
{
p0.r[j] = -p0.r[j];
p0.v[j] = -p0.v[j];
}
}
else
{
// Need to capture the fact that the acceleration switches direction relative to velocity half way through the timestep.
// Two approaches, either
// Try to compute the time of the bounce and work out the detail.
// OR
// Use conservation of energy to get the right speed - much easier!
if (p0.r[j] >= 250)
{
double energy = 0.5*p0.v[j] * p0.v[j] - G[j] * p0.r[j];
p0.r[j] = 500 - p0.r[j];
p0.v[j] = -sqrt(2 * (energy + G[j] * p0.r[j]));
}
else if (p0.r[j] <= 0)
{
double energy = 0.5*p0.v[j] * p0.v[j] - G[j] * p0.r[j];
p0.r[j] = -p0.r[j];
p0.v[j] = sqrt(2*(energy + G[j] * p0.r[j]));
}
}
energy += 0.5*p0.v[j] * p0.v[j] - G[j] * p0.r[j];
}
/////////////////////Output//////////////////
cout << energy << setw(10);
for (int j = 0; j <= 2; j++)
{
cout << p0.r[j] << setw(10);
}
for (int j = 0; j <= 2; j++)
{
cout << p0.v[j] << setw(10);
}
///////////////////////////////////////////////
cout << endl;
}
}
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).