Showing posts with label maths. Show all posts
Showing posts with label maths. Show all posts

Tuesday, 4 August 2020

Raw Graphics Engine : C++ Project

It has been a whilst since I had a personal improvement project grace these pages, so here's one I started over the weekend.... A graphics engine.

Sure this is something I play about with all day in the office, we're writing games!  That's literally my job, but I've been a system engineer for such a very long time, and I've seen all these sparkly things coming from folks working on game play and wanted some sparklies of my own.

I therefore began two projects, both are graphics engines, but they're very different from one another... one is in Vulkan, which is not what we're talking about here, no we're talking about the other one... And this is a graphics engine I've written myself.

It's gone through three phases since Saturday, Sunday and then just tonight.  The first phase was setting up the basic rendering, getting a triangle on the screen and making it flat (orthographic) projection.


The engine is written in C++, uses SDL2 for the window and renderer, but the engine itself does all the geometry transforms through linear matrix mathematics that I hand crafted, and it reaches into the third dimension in orthographic mode.



The shapes can be rotated, scaled, translated, the usual.  But before I drove myself mad with writing shapes by hand on graph paper, I wrote a very simple importer for the very simple Milkshape 3D model editor, and started with a sphere:



Milkshape has appeared on these pages before and is really the only modelling package I'm familiar with, I really do need to learn Blender don't I?

So with models loading I got a little adventurous:




This mesh really stresses my single core linear mathematics, so I started to switch it out in favour of GLM tonight:

// Model
glm::mat4 model(1.0f);
model = glm::translate(model, trans);
model = glm::rotate(model, glm::radians(angleZ), { 0, 0, 1 });
model = glm::rotate(model, glm::radians(angleY), { 0, 1, 0 });
model = glm::rotate(model, glm::radians(angleX), { 1, 0, 0 });
model = glm::scale(model, glm::vec3(scale.x, scale.y, scale.z));

So, that's been my three days.. I'm interested where and what I will do with this engine.


However, Vulkan, that's the other thing I'm learning.

Tuesday, 15 September 2015

GCSE Maths (8300) Foundation - A modern resit

I'm a little disappointed with myself, a friend of mine has just taken, or should I say, retaken his GCSE Maths papers, some twenty two years after this dismal first time around, and he's chuffed he got himself a C.

Now, he worked really hard at this, and good on him, I got a C in GCSE maths the first time around, and I am one of those people who think exams now are easier than back then, so my friend challenged me to open the exam board sample exam paper and do it...

So, I did, now I this was with no rehearsal, the Foundation paper, and unlike my exams, no calculator!... Yes, when I were a lad you always had your scientific calculator, but this exam has three papers, two with and one without, I was challenged to the one without (ironic for a computer programmer).

I set about the paper, and after 2 hours had finished, this was a 1 hour 30 minute paper, so a little worrying already, but we'll let that slide, and I also noted I had difficulty with fractional maths without a calculator, which I myself have always always reached for.

I had significant difficulty too as I've forgotten about simultaneous equations, I was proper scratching my head, the feeling that I knew it once was there, but the practical was gone... So I expected to have lost 6 marks already...

I was stunned therefore when told I'd scored just 50 from 79 marks.

Interestingly though one of the questions my mate did say my answer made more sense than the one in the answer paper, I'd used common sense rather than explain how I picked a median group... so he'd deducted two marks as there were no workings, but I'd gotten 1 of the 3 marks available for just being right... I personally feel I should get all three marks for just being right, lets face it, if you put down a good answer you knock confidence!  And I was right, somewhere in my noggin I crunched the figures and I was hard-wired to be right, why should that be penalised?

I've always thought the right answer should get full marks, and only if it's the wrong answer should the working be looked at, but this marking scheme was "A1" they got the answer, but only is "M1 and M2" in the workings... and I'm like, no... A1, they got it, it was right, they passed, stop pussy fucking footing around, they were right... And then if they were wrong, see how far wrong, and feed that back into your course for next year, if 20% of candidates get such and such wrong, but the workings look right, your course might have a fault, or you might have to clarify the teaching material, not punish the candidate who was right all along!

It beggars belief.

But I was truly surprised how hard the exam was, harder because of no calculator for me, but for a foundation level exam it was pretty comprehensive to me, and it has given me a better respect for those getting A's and A*'s today... They must bloody work hard, or at least have learned the procedures for the questions by rote.

The question I have, which remains is, what does 50/79 mean in terms of a grade?... Hmmm... I recon I'm in the C category again, just like I was first time around... Hey ho.

Wednesday, 20 November 2013

Maths: Zero Factorial in Code

Sometimes maths really confuses me... I have to be honest, I work with computers because I'm pretty good at asking them for results for things, and I know really quite well how to feed a calculation into the machine.

But, the source of these calculations is generally going to be mathematical and I find maths just to be so annoying...

Here's the information from Numberphile about Factorials...


Right, so they started with the factorial of 5 (5!) being 4 x 3 x 2 x 1 = 120.  And yes you can do this and ask your computer code to do it for you:

int factorial = 5 x 4 x 3 x 2 x 1;
cout << factorial;

Not problem, we can even write a program to do this function for us, quickly...

int factorial (const int& p_Factorial)
{
int l_result = p_Factorial;
int l_temp = p_Factorial - 1;
while ( l_temp > 0 )
{
l_result = l_result * l_temp;
l_temp--;
}
return l_result;
}

This code follows the first example they give in the video, and it presents correct results for all factorials of 1 and above.  This also matches with the graph drawn in the video.

This also goes back to what is stated in the video around the 0:45 second mark... "you can go down to 3 x 2 x 1", does Dr Grime mean you can take factorials down to one?  If so, then this code is correct, and this rule controls the while loop in there.

Except of course zero raises its ugly head, and breaks everything, now to explain zero the pattern above is not followed, a new pattern is invented, and this is where it gets sticky for computers and my brain, because the new pattern is not multiplication, its division...

If we approach the pattern above as multiplication, then my brain tells me the pattern, the parameter even, for the function starts 0, and then ends.  So to my mind zero factorial is immediately zero and the function ends:

int factorial (const int& p_Factorial)
{
int l_result = p_Factorial;
if ( p_Factorial > 0 )
{
int l_temp = p_Factorial - 1;

while ( l_temp > 0 )
{
l_result = l_result * l_temp;
l_temp--;
}
}
return l_result;
}

Or in fact I'd like to make the function throw an "invalid argument" and only let it calculate for integers of value one and above.

But this is not the pattern held to, no as you can see the pattern becomes "Take a factorial you've not calculated and use it as a parameter into the local calculation" this is a bit alien to a programming language function, take something you've not calculated as the parameter... what?

So, the function becomes something cyclic, or even two functions:

int factorialPreStep (const int& p_Factorial)
{
int l_result = p_Factorial;
if ( p_Factorial > 0 )
{
int l_temp = p_Factorial - 1;

while (l_temp > 0)
{
l_result = l_result * l_temp;
l_temp--;
}
}
return l_result;
}

int factorial (const int& p_Factorial)
{
int l_result = factorialPreStep(p_Factorial+1);
l_result = l_result / (p_Factorial + 1);
return l_result;
}

Now, the function "factorial" will always need to be passed 0 or higher, and it'll therefore always pass 1 or higher to the pre-calculation.

The full application therefore is:

#include <iostream>

using namespace std;

int factorialPreStep (const int& p_Factorial)
{
int l_result = p_Factorial;
if ( p_Factorial > 0 )
{
int l_temp = p_Factorial - 1;

do
{
l_result = l_result * l_temp;
l_temp--;
}
while ( l_temp > 0 );
}
return l_result;
}

int factorial (const int& p_Factorial)
{
int l_result = factorialPreStep(p_Factorial+1);

l_result = l_result / (p_Factorial+1);

return l_result;
}

int main (int p_argc, char** p_argv)
{
    cout << factorial(5) << endl;
    cout << factorial(4) << endl;
    cout << factorial(3) << endl;
    cout << factorial(2) << endl;
    cout << factorial(1) << endl;

    return 0;
}

And we see the output:


Right, so this code works?  With zero?...... HMmmm, lets see....


Yes, it works for zero factorial, which as per the video comes out as one, but this was by using the division pattern... 1 / 1 = 1, that's fair I get that... But it is not the same as the original multiplication pattern.

The original pattern, the original function, is a x b x c... so 5 x 4 x 3 x 2 x 1.... What is that pattern for one factorial?... Well the pattern is just 1... so what's the pattern for 0... well it's bleeding 0....

As a programmer this is an obvious avenue of research, we like to find multiple ways to get the same result, usually so we can find the most efficient solution for runtime, but what we don't like is two seemingly matching patterns, giving different results...

So for this code we could have written:

    cout << factorial(5) << endl;
    cout << factorial(4) << endl;
    cout << factorial(3) << endl;
    cout << factorial(2) << endl;
    cout << factorial(1) << endl;

as:

    cout << (5 * 4 * 3 * 2 * 1) << endl;
    cout << (4 * 3 * 2 * 1) << endl;
    cout << (3 * 2 * 1) << endl;
    cout << (2 * 1) << endl;
    cout << (1) << endl;
    
The pattern is right, the results are right, the code is right, but then we add 0!...

    cout << (0) << endl;
    
And it most certainly is not right, the pattern is broken, so was it a valid pattern?  Well it must have been because we use this pattern in our loop to calculate the prefactorial step...

Argh, see my head just exploded.... I hate maths for this.

And it only hurts my head more as I understand my solution code, and that solution code works... GRRRR.