I had made the following code to solve a cubic equation which uses couple ‘math’ functions:

```
#define pi 3.141593
struct real_solutions_t {
uint8_t number_of_solutions;
float solutions[3];
};
uint8_t solve_cubic(float a, float b, float c, float d, struct real_solutions_t *soln)
{
float _a, _b, _c;
float half = 1.0 / 2;
float third = 1.0 / 3;
if (a != 0) {
_a = b / a;
_b = c / a;
_c = d / a;
}
else {
return 0; //not a cubic funtions
}
float p = _b - ((_a * _a) / 3);
float q = ((2 * _a * _a * _a) / 27) - ((_a * _b) / 3) + _c;
float disciminant = ((q * q) / 4) + ((p * p * p) / 27);
if (disciminant > 0.000001) { //inplace of 'disciminant > 0' to due to floating point computation accuracy.
//else may result in incorrect output if 'disciminant = 0'
soln->number_of_solutions = 1; //one real solution
soln->solutions[0] = pow((pow(disciminant, half) - (q / 2)), third) + pow((-1 * (pow(disciminant, half)) - (q / 2)), third) - (_a / 3);
}
else if (disciminant < 0 ) {
p = pow((-1 * p), half);
float f = (2 / pow(3, half)) * p;
float g = (3 / 2) * pow(3, half);
soln->number_of_solutions = 3; //3 real solutions
soln->solutions[0] = f * sin(third * asin((g * q) / (p * p * p))) - (_a / 3);
soln->solutions[1] = f * sin(third * asin(((g * q) / (p * p * p))) + (pi / 3)) - (_a / 3);
soln->solutions[2] = f * cos(third * asin(((g * q) / (p * p * p))) + (pi / 6)) - (_a / 3);
}
else { //assumes 'disciminant = 0'
soln->number_of_solutions = 2; //2 real solutions (x2 = x3, repeated root)
if (q < 0) {
q *= -1;
soln->solutions[0] = (2 * pow((q / 2), third)) - (_a / 3);
soln->solutions[1] = (-1 * pow((q / 2), third)) - (_a / 3);
}
else {
soln->solutions[0] = (-2 * pow((q / 2), third)) - (_a / 3);
soln->solutions[1] = pow((q / 2), third) - (_a / 3);
}
}
return 1;
}
void setup() {
struct real_solutions_t real_solutions;
Serial.begin(115200);
uint8_t i = solve_cubic(1, -4, 5, -2, &real_solutions);
if (i) {
Serial.print("Number of Real Solutions: ");
Serial.println(real_solutions.number_of_solutions);
if (real_solutions.number_of_solutions == 1) {
Serial.print("x = ");
Serial.println(real_solutions.solutions[0]);
}
else if (real_solutions.number_of_solutions == 2) {
Serial.print("x1 = ");
Serial.println(real_solutions.solutions[0]);
Serial.print("x2 = x3 = ");
Serial.println(real_solutions.solutions[1]);
}
else {
Serial.print("x1 = ");
Serial.println(real_solutions.solutions[0]);
Serial.print("x2 = ");
Serial.println(real_solutions.solutions[1]);
Serial.print("x3 = ");
Serial.println(real_solutions.solutions[2]);
}
}
else {
Serial.println(F("NOT A CUBIC EQUATION!"));
}
}
void loop() {
//nothing here
}
```

*Sketch uses 3140 bytes (9%) of program storage space. Maximum is 32256 bytes.*

*Global variables use 244 bytes (11%) of dynamic memory, leaving 1804 bytes for local variables. Maximum is 2048 bytes.*

The above code compiled and uploaded OK for my UNO but could not get any sensible output on Serial monitor.

I then used change the the code to use the F() functions wherever possible:

```
#define pi 3.141593
struct real_solutions_t {
uint8_t number_of_solutions;
float solutions[3];
};
uint8_t solve_cubic(float a, float b, float c, float d, struct real_solutions_t *soln)
{
float _a, _b, _c;
float half = 1.0 / 2;
float third = 1.0 / 3;
if (a != 0) {
_a = b / a;
_b = c / a;
_c = d / a;
}
else {
return 0; //not a cubic funtions
}
float p = _b - ((_a * _a) / 3);
float q = ((2 * _a * _a * _a) / 27) - ((_a * _b) / 3) + _c;
float disciminant = ((q * q) / 4) + ((p * p * p) / 27);
if (disciminant > 0.000001) { //inplace of 'disciminant > 0' to due to floating point computation accuracy.
//else may result in incorrect output if 'disciminant = 0'
soln->number_of_solutions = 1; //one real solution
soln->solutions[0] = pow((pow(disciminant, half) - (q / 2)), third) + pow((-1 * (pow(disciminant, half)) - (q / 2)), third) - (_a / 3);
}
else if (disciminant < 0 ) {
p = pow((-1 * p), half);
float f = (2 / pow(3, half)) * p;
float g = (3 / 2) * pow(3, half);
soln->number_of_solutions = 3; //3 real solutions
soln->solutions[0] = f * sin(third * asin((g * q) / (p * p * p))) - (_a / 3);
soln->solutions[1] = f * sin(third * asin(((g * q) / (p * p * p))) + (pi / 3)) - (_a / 3);
soln->solutions[2] = f * cos(third * asin(((g * q) / (p * p * p))) + (pi / 6)) - (_a / 3);
}
else { //assumes 'disciminant = 0'
soln->number_of_solutions = 2; //2 real solutions (x2 = x3, repeated root)
if (q < 0) {
q *= -1;
soln->solutions[0] = (2 * pow((q / 2), third)) - (_a / 3);
soln->solutions[1] = (-1 * pow((q / 2), third)) - (_a / 3);
}
else {
soln->solutions[0] = (-2 * pow((q / 2), third)) - (_a / 3);
soln->solutions[1] = pow((q / 2), third) - (_a / 3);
}
}
return 1;
}
void setup() {
struct real_solutions_t real_solutions;
Serial.begin(115200);
uint8_t i = solve_cubic(1, -4, 5, -2, &real_solutions);
if (i) {
Serial.print(F("Number of Real Solutions: "));
Serial.println(real_solutions.number_of_solutions);
if (real_solutions.number_of_solutions == 1) {
Serial.print(F("x = "));
Serial.println(real_solutions.solutions[0]);
}
else if (real_solutions.number_of_solutions == 2) {
Serial.print(F("x1 = "));
Serial.println(real_solutions.solutions[0]);
Serial.print(F("x2 = x3 = "));
Serial.println(real_solutions.solutions[1]);
}
else {
Serial.print(F("x1 = "));
Serial.println(real_solutions.solutions[0]);
Serial.print(F("x2 = "));
Serial.println(real_solutions.solutions[1]);
Serial.print(F("x3 = "));
Serial.println(real_solutions.solutions[2]);
}
}
else {
Serial.println(F("NOT A CUBIC EQUATION!"));
}
}
void loop() {
//nothing here
}
```

*Sketch uses 3206 bytes (9%) of program storage space. Maximum is 32256 bytes.*

*Global variables use 200 bytes (9%) of dynamic memory, leaving 1848 bytes for local variables. Maximum is 2048 bytes.*

This too compiled OK but now I was getting the correct output on Serial monitor!

So I made me think that is “It must have been RAM related then”… Was my assumption right?

If so, how to determine is there is sufficient ‘free’ RAM left on a given arduino board to have confidence that a code using ‘math’ functions with execute correctly?

Any insights?