i'm writing a graphics engine as an assignment for university and recently tried to optimize a part of my code, however the optimization seems to slow it down instead.
This specific part of code processes 2D Lindenmayer systems and turns them into a list of "line2D" objects that can be processed into an image by another part of the program.
In doing that it uses a sin and cos to calculate the coordinates of the next point, and because sin and cos are floating point operations i figured these would be time intensive, especially in more complex lindenmayer systems. so I created an object class "cossinlist" which imports the valus of cos and sin from a .txt file for every integer angle between 0 and 359 degrees (transformed to rad) to two maps called "coslist" and "sinlist" with the angle as key. That way I'd only have to do the actual flops when dealing with an angle that contains a decimal part.
Then i decided to measure the execution time with the optimization and without it (by commenting it out) on a relatively intensive system: with it the engine generated the image in 33.4016 seconds and without it only took 25.3686 seconds. this is a substantial difference, however not in the expected way. I did more tests and all of them gave similiar proportions of difference, so now im wondering... What causes this difference?
The function:
img::EasyImage LSystem2D(const unsigned int size, const ini::DoubleTuple & backgroundcolor, LParser::LSystem2D & System, const ini::DoubleTuple & color)
{
CosSinList cossinlist;
std::string string;
Lines2D Lines;
double origin = 0;
Point2D currentpos(origin, origin);
Point2D newpos(origin, origin);
std::stack<Point2D> savedpositions;
double currentangle = System.get_starting_angle();
std::stack<double> savedangles;
const img::Color linecolor(color.at(0)*255,color.at(1)*255,color.at(2)*255);
const img::Color BGcolor(backgroundcolor.at(0)*255,backgroundcolor.at(1)*255,backgroundcolor.at(2)*255);
string = ReplaceLsystem(System, (System.get_initiator()), (System.get_nr_iterations()));
bool optimizedangle = false;
if(System.get_angle() == rint(System.get_angle()) && (System.get_starting_angle() == rint(System.get_starting_angle()))
{
optimizedangle = true;
}
for(char& c : string)
{
if(currentangle > 359){currentangle -= 360;}
if(currentangle < -359){currentangle += 360;}
if(System.get_alphabet().count(c) != 0)
{
/*if(optimizedangle == true)
{
if(currentangle >= 0)
{
newpos.X = currentpos.X+(cossinlist.coslist[currentangle]);
newpos.Y = currentpos.Y+(cossinlist.sinlist[currentangle]);
}
else
{
newpos.X = currentpos.X+(cossinlist.coslist[360+currentangle]);
newpos.Y = currentpos.Y+(cossinlist.sinlist[360+currentangle]);
}
}
else
{*/
newpos.X = currentpos.X+cos(currentangle*PI/180);
newpos.Y = currentpos.Y+sin(currentangle*PI/180);
//}
if(System.draw(c))
{
Lines.push_back(Line2D(currentpos,newpos,linecolor));
currentpos = newpos;
}
else
{
currentpos = newpos;
}
}
else if(c=='-')
{
currentangle -= System.get_angle();
}
else if(c=='+')
{
currentangle += System.get_angle();
}
else if(c=='[')
{
savedpositions.push(currentpos);
savedangles.push(currentangle);
}
else if(c==']')
{
currentpos = savedpositions.top();
savedpositions.pop();
currentangle = savedangles.top();
savedangles.pop();
}
}
return Drawlines2D(Lines, size, BGcolor);
}
The SinCosList class:
#include <fstream>
#include <iostream>
#include <map>
#include "CosSinList.h"
using namespace std;
CosSinList::CosSinList()
{
string line;
std::fstream cosstream("coslist.txt", std::ios_base::in);
double a;
double i = 0;
while (cosstream >> a)
{
coslist[i] = a;
i += 1;
}
std::fstream sinstream("sinlist.txt", std::ios_base::in);
i = 0;
while (sinstream >> a)
{
sinlist[i] = a;
i += 1;
}
};
CosSinList::~CosSinList(){};
The "optimization" is commented out in the same way i commented it out during the speed test, only the actual use of the object is commented out (the SinCosList is still being initialized and the boolean that checks if it can be used is also still being initialized)