Nouvelles:

Le Forum est maintenant chiffré (préambule https). Bien sûr, des liens externes insérés dans les sujets vont demeurer inchangés. Mais la composition des pages du Forum est désormais sécurisée. Si des problèmes d'affichage surviennent, veillez à vider votre cache pour ce site.

Menu principal

Programmer sans <math.h>

Démarré par sylvainmahe, Décembre 31, 2020, 10:50:42 AM

« précédent - suivant »

sylvainmahe

Bonjour à  vous,

Je souhaite partager avec vous un travail amateur autodidacte que j'ai titré : Programmer sans <math.h>

(cette proposition s'adresse au langage C++ à  destination de microcontrôleurs, mais est facilement applicable au C ou à  tout autre langage de programmation)


En électronique numérique embarquée qui met en oeuvre des calculateurs programmables, et plus largement en programmation générale C++ (le langage utilisé pour écrire les fonctions énoncées ici), la logique pure est généralement accompagnée de calculs arithmétiques pour mener à  bien la plupart des projets. Pour se faire, les calculateurs utilisés (soit les microcontrôleurs) sont équipés chacun d'une unité arithmétique et logique, partie du circuit intégré dédiée à  de telles opérations, mais ce matériel ne permet pas d'effectuer des opérations arithmétiques autres que les calculs élémentaires, soit les additions, les soustractions, les multiplications, ou les divisions :

Comprendre que des opérations plus complexes comme par exemple sinus ou cosinus (que l'on retrouve habituellement dans les calculatrices modernes), ne sont pas câblées dans ce type de circuit intégré (comme c'est le cas dans la majorité des microcontrôleurs).

En conséquence, les opérations mathématiques plus élaborées doivent être écrites manuellement lors de la programmation logicielle, ceci en utilisant un certain nombre d'instructions logiques de base (structures conditionnelles, comparaisons, décalages) et d'instructions arithmétiques simples (additions, soustractions, multiplications, et divisions), seules disponibles dans les architectures matérielles des microcontrôleurs.

Cette recherche et construction logicielle effectuée, toutes les opérations (dont les ensembles constituent les algorithmes) qui oeuvrent dans le fonctionnement intime de sinus ou cosinus (pour reprendre l'exemple) peuvent pour une question pratique de lisibilité et portabilité du programme être encapsulées dans des fonctions autonomes dédiées, autrement-dit regroupées dans des blocs de code distincts contenant chacun toutes les opérations nécessaires à  leur fonctionnement interne, de sorte de pouvoir à  posteriori en faire usage facilement en un minimum de lignes de programmation, ceci sans avoir besoin de ressources annexes externes. C'est ce que permettent les fonctions mathématiques décrites ci-dessous.

Descriptif des fonctions mathématiques :

- floor : arrondit un nombre décimal à  l'entier inférieur.
- round : arrondit un nombre décimal à  l'entier le plus proche.
- ceil : arrondit un nombre décimal à  l'entier supérieur.
- curve : créé des interpolations linéaires ou non linéaires de courbes.
- wurve : créé des interpolations linéaires ou non linéaires dissymétriques de courbes.
- range : cadre une valeur dans un intervalle.
- center : calcule la moyenne de deux valeurs.
- pow : calcule la puissance d'un nombre.
- sqrt : calcule la racine carrée d'un nombre.
- fact : calcule la factorielle d'un nombre.
- sin : trouve le sinus d'un angle.
- cos : trouve le cosinus d'un angle.
- tan : trouve la tangente d'un angle.
- arcsin : trouve l'angle à  partir d'un sinus.
- arccos : trouve l'angle à  partir d'un cosinus.
- arctan : trouve l'angle à  partir d'une tangente.
- arctan2 : trouve l'angle à  partir de la tangente de deux arguments x et y.

Il est important d'appréhender que les fonctions mathématiques implémentées ne sont qu'une des façons possibles d'effectuer les calculs et résoudre les fonctions énoncées, ceci dans un certain langage de programmation (le C++), et d'une manière subjective avec une approche et une résolution des problématiques tout à  fait singulière et arbitraire, modeste expression partagée libre et ouverte de son auteur.





Détails des fonctions

Fonction floor :
signed long floor (const float VALUE)
{
signed long value = 0;

if (VALUE <= 0)
{
value = VALUE - 1.0;
}
else
{
value = VALUE;
}

return value;
}


Fonction round :
signed long round (const float VALUE)
{
signed long value = 0;

if (VALUE <= 0)
{
value = VALUE - 0.5;
}
else
{
value = VALUE + 0.5;
}

return value;
}


Fonction ceil :
signed long ceil (const float VALUE)
{
signed long value = 0;

if (VALUE <= 0)
{
value = VALUE;
}
else
{
value = VALUE + 1.0;
}

return value;
}


Fonction curve :
float curve (const float POSITION_START, const float POSITION_CURRENT, const float POSITION_END, const float INTERPOLATION_START, const float INTERPOLATION_END, const float CURVE)
{
float value = 0;

if ((POSITION_START < POSITION_END && POSITION_CURRENT <= POSITION_START) || (POSITION_START > POSITION_END && POSITION_CURRENT >= POSITION_START))
{
value = INTERPOLATION_START;
}
else if ((POSITION_START < POSITION_END && POSITION_CURRENT >= POSITION_END) || (POSITION_START > POSITION_END && POSITION_CURRENT <= POSITION_END))
{
value = INTERPOLATION_END;
}
else
{
if (INTERPOLATION_END > INTERPOLATION_START)
{
if (CURVE == 0)
{
value = INTERPOLATION_START + ((INTERPOLATION_END - INTERPOLATION_START) * ((POSITION_CURRENT - POSITION_START) / (POSITION_END - POSITION_START)));
}
else if (CURVE > 0)
{
value = INTERPOLATION_START + (((INTERPOLATION_END - INTERPOLATION_START) * ((POSITION_CURRENT - POSITION_START) / (POSITION_END - POSITION_START))) / ((CURVE + 1.0) - (CURVE * ((POSITION_CURRENT - POSITION_START) / (POSITION_END - POSITION_START)))));
}
else
{
value = INTERPOLATION_END - (((INTERPOLATION_END - INTERPOLATION_START) * ((POSITION_CURRENT - POSITION_END) / (POSITION_START - POSITION_END))) / (1.0 + (-CURVE * ((POSITION_CURRENT - POSITION_START) / (POSITION_END - POSITION_START)))));
}
}
else
{
if (CURVE == 0)
{
value = INTERPOLATION_START - ((INTERPOLATION_START - INTERPOLATION_END) * ((POSITION_CURRENT - POSITION_START) / (POSITION_END - POSITION_START)));
}
else if (CURVE > 0)
{
value = INTERPOLATION_START - (((INTERPOLATION_START - INTERPOLATION_END) * ((POSITION_CURRENT - POSITION_START) / (POSITION_END - POSITION_START))) / ((CURVE + 1.0) - (CURVE * ((POSITION_CURRENT - POSITION_START) / (POSITION_END - POSITION_START)))));
}
else
{
value = INTERPOLATION_END + (((INTERPOLATION_START - INTERPOLATION_END) * ((POSITION_CURRENT - POSITION_END) / (POSITION_START - POSITION_END))) / (1.0 + (-CURVE * ((POSITION_CURRENT - POSITION_START) / (POSITION_END - POSITION_START)))));
}
}
}

return value;
}


Fonction wurve :
float wurve (const float POSITION_START, const float POSITION_CURRENT, const float POSITION_END, const float INTERPOLATION_START, const float INTERPOLATION_CENTER, const float INTERPOLATION_END, const float CURVE_START, const float CURVE_END)
{
const float POSITION_CENTER = POSITION_START + ((POSITION_END - POSITION_START) / 2.0);
float value = 0;

if ((POSITION_START < POSITION_END && POSITION_CURRENT < POSITION_CENTER) || (POSITION_START > POSITION_END && POSITION_CURRENT > POSITION_CENTER))
{
if ((POSITION_START < POSITION_CENTER && POSITION_CURRENT <= POSITION_START) || (POSITION_START > POSITION_CENTER && POSITION_CURRENT >= POSITION_START))
{
value = INTERPOLATION_START;
}
else if ((POSITION_START < POSITION_CENTER && POSITION_CURRENT >= POSITION_CENTER) || (POSITION_START > POSITION_CENTER && POSITION_CURRENT <= POSITION_CENTER))
{
value = INTERPOLATION_CENTER;
}
else
{
if (INTERPOLATION_CENTER > INTERPOLATION_START)
{
if (CURVE_START == 0)
{
value = INTERPOLATION_START + ((INTERPOLATION_CENTER - INTERPOLATION_START) * ((POSITION_CURRENT - POSITION_START) / (POSITION_CENTER - POSITION_START)));
}
else if (CURVE_START > 0)
{
value = INTERPOLATION_CENTER - (((INTERPOLATION_CENTER - INTERPOLATION_START) * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_START - POSITION_CENTER))) / (1.0 + (CURVE_START * ((POSITION_CURRENT - POSITION_START) / (POSITION_CENTER - POSITION_START)))));
}
else
{
value = INTERPOLATION_START + (((INTERPOLATION_CENTER - INTERPOLATION_START) * ((POSITION_CURRENT - POSITION_START) / (POSITION_CENTER - POSITION_START))) / ((-CURVE_START + 1.0) - (-CURVE_START * ((POSITION_CURRENT - POSITION_START) / (POSITION_CENTER - POSITION_START)))));
}
}
else
{
if (CURVE_START == 0)
{
value = INTERPOLATION_START - ((INTERPOLATION_START - INTERPOLATION_CENTER) * ((POSITION_CURRENT - POSITION_START) / (POSITION_CENTER - POSITION_START)));
}
else if (CURVE_START > 0)
{
value = INTERPOLATION_CENTER + (((INTERPOLATION_START - INTERPOLATION_CENTER) * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_START - POSITION_CENTER))) / (1.0 + (CURVE_START * ((POSITION_CURRENT - POSITION_START) / (POSITION_CENTER - POSITION_START)))));
}
else
{
value = INTERPOLATION_START - (((INTERPOLATION_START - INTERPOLATION_CENTER) * ((POSITION_CURRENT - POSITION_START) / (POSITION_CENTER - POSITION_START))) / ((-CURVE_START + 1.0) - (-CURVE_START * ((POSITION_CURRENT - POSITION_START) / (POSITION_CENTER - POSITION_START)))));
}
}
}
}
else if ((POSITION_START < POSITION_END && POSITION_CURRENT > POSITION_CENTER) || (POSITION_START > POSITION_END && POSITION_CURRENT < POSITION_CENTER))
{
if ((POSITION_CENTER < POSITION_END && POSITION_CURRENT <= POSITION_CENTER) || (POSITION_CENTER > POSITION_END && POSITION_CURRENT >= POSITION_CENTER))
{
value = INTERPOLATION_CENTER;
}
else if ((POSITION_CENTER < POSITION_END && POSITION_CURRENT >= POSITION_END) || (POSITION_CENTER > POSITION_END && POSITION_CURRENT <= POSITION_END))
{
value = INTERPOLATION_END;
}
else
{
if (INTERPOLATION_END > INTERPOLATION_CENTER)
{
if (CURVE_END == 0)
{
value = INTERPOLATION_CENTER + ((INTERPOLATION_END - INTERPOLATION_CENTER) * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_END - POSITION_CENTER)));
}
else if (CURVE_END > 0)
{
value = INTERPOLATION_CENTER + (((INTERPOLATION_END - INTERPOLATION_CENTER) * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_END - POSITION_CENTER))) / ((CURVE_END + 1.0) - (CURVE_END * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_END - POSITION_CENTER)))));
}
else
{
value = INTERPOLATION_END - (((INTERPOLATION_END - INTERPOLATION_CENTER) * ((POSITION_CURRENT - POSITION_END) / (POSITION_CENTER - POSITION_END))) / (1.0 + (-CURVE_END * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_END - POSITION_CENTER)))));
}
}
else
{
if (CURVE_END == 0)
{
value = INTERPOLATION_CENTER - ((INTERPOLATION_CENTER - INTERPOLATION_END) * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_END - POSITION_CENTER)));
}
else if (CURVE_END > 0)
{
value = INTERPOLATION_CENTER - (((INTERPOLATION_CENTER - INTERPOLATION_END) * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_END - POSITION_CENTER))) / ((CURVE_END + 1.0) - (CURVE_END * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_END - POSITION_CENTER)))));
}
else
{
value = INTERPOLATION_END + (((INTERPOLATION_CENTER - INTERPOLATION_END) * ((POSITION_CURRENT - POSITION_END) / (POSITION_CENTER - POSITION_END))) / (1.0 + (-CURVE_END * ((POSITION_CURRENT - POSITION_CENTER) / (POSITION_END - POSITION_CENTER)))));
}
}
}
}
else
{
value = INTERPOLATION_CENTER;
}

return value;
}


Fonction range :
float range (const float RANGE_START, const float VALUE_CURRENT, const float RANGE_END)
{
float value = 0;

if (RANGE_START < RANGE_END)
{
if (VALUE_CURRENT <= RANGE_START)
{
value = RANGE_START;
}
else if (VALUE_CURRENT >= RANGE_END)
{
value = RANGE_END;
}
else
{
value = VALUE_CURRENT;
}
}
else if (RANGE_START > RANGE_END)
{
if (VALUE_CURRENT <= RANGE_END)
{
value = RANGE_END;
}
else if (VALUE_CURRENT >= RANGE_START)
{
value = RANGE_START;
}
else
{
value = VALUE_CURRENT;
}
}
else
{
value = RANGE_START;
}

return value;
}


Fonction center :
float center (const float VALUE_START, const float VALUE_END)
{
float value = 0;

if (VALUE_START == VALUE_END)
{
value = VALUE_START;
}
else
{
value = VALUE_START + ((VALUE_END - VALUE_START) / 2.0);
}

return value;
}


Fonction pow :
float pow (const float VALUE, const signed long EXPONENT)
{
signed long iterationPower = 0;
float value = 0;

if (EXPONENT < 0)
{
if (VALUE < 0)
{
value = -VALUE;
}
else
{
value = VALUE;
}

for (iterationPower = -1; iterationPower > EXPONENT; iterationPower--)
{
value *= VALUE;
}

value = 1.0 / value;

if (VALUE < 0)
{
value = -value;
}
}
else if (EXPONENT == 0)
{
if (VALUE < 0)
{
value = -1;
}
else
{
value = 1;
}
}
else
{
if (VALUE < 0)
{
value = -VALUE;
}
else
{
value = VALUE;
}

for (iterationPower = 1; iterationPower < EXPONENT; iterationPower++)
{
value *= VALUE;
}

if (VALUE < 0)
{
value = -value;
}
}

return value;
}


Fonction sqrt :
float sqrt (const float RADICAND)
{
unsigned char iterationPrecision = 0;
float searchDecimal = 0.1;
float foundDecimal = 0;
bool quickSearch = false;
unsigned long searchInteger = 1000;
unsigned int incrementInteger = 1000;
float sr1 = 0;
float sr2 = 0;
float sr3 = 0;
float value = 0;

if (RADICAND < 1)
{
while (searchDecimal * searchDecimal <= RADICAND)
{
searchDecimal += 0.1;
}

for (iterationPrecision = 0; iterationPrecision < 4; iterationPrecision++)
{
foundDecimal = ((RADICAND / searchDecimal) + searchDecimal) / 2.0;
searchDecimal = foundDecimal;
}

value = foundDecimal;
}
else if (RADICAND == 1)
{
value = 1;
}
else
{
while (quickSearch == false)
{
while (searchInteger * searchInteger <= RADICAND)
{
searchInteger += incrementInteger;
}

searchInteger -= incrementInteger;

if (incrementInteger == 1)
{
quickSearch = true;
}
else
{
incrementInteger /= 10;
}
}

sr1 = RADICAND - (float (searchInteger) * float (searchInteger));
sr2 = sr1 / (2.0 * float (searchInteger));
sr3 = float (searchInteger) + sr2;

value = sr3 - ((sr2 * sr2) / (2.0 * sr3));
}

return value;
}


Fonction fact :
unsigned long long fact (const unsigned long INTEGER)
{
unsigned long iterationFactorial = 1;
unsigned long long value = 1;

for (iterationFactorial = 1; iterationFactorial <= INTEGER; iterationFactorial++)
{
value *= iterationFactorial;
}

return value;
}


Fonction sin :
float sin (const float ANGLE)
{
unsigned long iterationModulo = 0;
unsigned long foundMultiply = 0;
bool quickSearch = false;
float angle = 0;
float alpha = 0;
float alpha2 = 0;
float alpha3 = 0;
float alpha5 = 0;
float sinus = 0;

if (ANGLE >= -180 && ANGLE <= 180)
{
angle = ANGLE;
}
else if (ANGLE < -180)
{
while (quickSearch == false)
{
for (iterationModulo = 1; ANGLE + (360.0 * (float (foundMultiply) + float (iterationModulo))) < -180; iterationModulo *= 10)
{
}

if (iterationModulo == 1)
{
quickSearch = true;
}
else
{
foundMultiply += iterationModulo / 10ul;
}
}

foundMultiply++;

angle = ANGLE + (360.0 * float (foundMultiply));
}
else
{
while (quickSearch == false)
{
for (iterationModulo = 1; ANGLE - (360.0 * (float (foundMultiply) + float (iterationModulo))) > 180; iterationModulo *= 10)
{
}

if (iterationModulo == 1)
{
quickSearch = true;
}
else
{
foundMultiply += iterationModulo / 10ul;
}
}

foundMultiply++;

angle = ANGLE - (360.0 * float (foundMultiply));
}

if (angle == -90 || angle == 270)
{
sinus = -1;
}
else if (angle == -270 || angle == 90)
{
sinus = 1;
}
else if (angle != -360 && angle != -180 && angle != 0 && angle != 180 && angle != 360)
{
alpha = angle * 0.0174532925199432;

alpha2 = alpha * alpha;
alpha3 = alpha2 * alpha;
alpha5 = alpha2 * alpha3;

sinus = alpha - (alpha3 / 6.0) + (alpha5 / 120.0) - ((alpha2 * alpha5) / 5040.0);
}

return sinus;
}


Fonction cos :
float cos (const float ANGLE)
{
unsigned long iterationModulo = 0;
unsigned long foundMultiply = 0;
bool quickSearch = false;
float angle = 0;
float alpha = 0;
float alpha2 = 0;
float alpha4 = 0;
float cosinus = 0;

if (ANGLE >= -180 && ANGLE <= 180)
{
angle = ANGLE;
}
else if (ANGLE < -180)
{
while (quickSearch == false)
{
for (iterationModulo = 1; ANGLE + (360.0 * (float (foundMultiply) + float (iterationModulo))) < -180; iterationModulo *= 10)
{
}

if (iterationModulo == 1)
{
quickSearch = true;
}
else
{
foundMultiply += iterationModulo / 10ul;
}
}

foundMultiply++;

angle = ANGLE + (360.0 * float (foundMultiply));
}
else
{
while (quickSearch == false)
{
for (iterationModulo = 1; ANGLE - (360.0 * (float (foundMultiply) + float (iterationModulo))) > 180; iterationModulo *= 10)
{
}

if (iterationModulo == 1)
{
quickSearch = true;
}
else
{
foundMultiply += iterationModulo / 10ul;
}
}

foundMultiply++;

angle = ANGLE - (360.0 * float (foundMultiply));
}

if (angle == -180 || angle == 180)
{
cosinus = -1;
}
else if (angle == -360 || angle == 0 || angle == 360)
{
cosinus = 1;
}
else if (angle != -270 && angle != -90 && angle != 90 && angle != 270)
{
alpha = angle * 0.0174532925199432;

alpha2 = alpha * alpha;
alpha4 = alpha2 * alpha2;

cosinus = 1.0 - ((alpha2 / 2.0) - (alpha4 / 24.0) + ((alpha2 * alpha4) / 720.0) - ((alpha4 * alpha4) / 40320.0));
}

return cosinus;
}


Fonction tan :
float tan (const float ANGLE)
{
unsigned long iterationModulo = 0;
unsigned long foundMultiply = 0;
bool quickSearch = false;
float angle = 0;
float alpha = 0;
float alpha2 = 0;
float alpha3 = 0;
float alpha5 = 0;
float tangent = 0;

if (ANGLE >= -90 && ANGLE <= 90)
{
angle = ANGLE;
}
else if (ANGLE < -90)
{
while (quickSearch == false)
{
for (iterationModulo = 1; ANGLE + (180.0 * (float (foundMultiply) + float (iterationModulo))) < -90; iterationModulo *= 10)
{
}

if (iterationModulo == 1)
{
quickSearch = true;
}
else
{
foundMultiply += iterationModulo / 10ul;
}
}

foundMultiply++;

angle = ANGLE + (180.0 * float (foundMultiply));
}
else
{
while (quickSearch == false)
{
for (iterationModulo = 1; ANGLE - (180.0 * (float (foundMultiply) + float (iterationModulo))) > 90; iterationModulo *= 10)
{
}

if (iterationModulo == 1)
{
quickSearch = true;
}
else
{
foundMultiply += iterationModulo / 10ul;
}
}

foundMultiply++;

angle = ANGLE - (180.0 * float (foundMultiply));
}

if (angle == -45)
{
tangent = -1;
}
else if (angle == -90 || angle == 0 || angle == 90)
{
tangent = 0;
}
else if (angle == 45)
{
tangent = 1;
}
else
{
if (angle > -45 && angle < 45)
{
alpha = angle * 0.0174532925199432;
}
else
{
if (angle < 0)
{
alpha = (-90.0 - angle) * 0.0174532925199432;
}
else
{
alpha = (90.0 - angle) * 0.0174532925199432;
}
}

alpha2 = alpha * alpha;
alpha3 = alpha2 * alpha;
alpha5 = alpha2 * alpha3;

if (angle > -45 && angle < 45)
{
tangent = alpha + ((alpha3 / 3.0) + ((2.0 * alpha5) / 15.0) + ((17.0 * (alpha5 * alpha2)) / 315.0));
}
else
{
tangent = 1.0 / (alpha + ((alpha3 / 3.0) + ((2.0 * alpha5) / 15.0) + ((17.0 * (alpha5 * alpha2)) / 315.0)));
}
}

return tangent;
}


Fonction arcsin :
float arcsin (const float SINUS)
{
float angle = 0;
float anglePrevious = 0;
float sinus = 0;
float sinusPositive = 0;
float alpha = 0;
float alpha2 = 0;
float alpha3 = 0;
float alpha5 = 0;
float incrementAngle = 10;
unsigned char decimal = 0;
unsigned char error = 0;
bool quickSearch = false;

if (SINUS <= -1)
{
angle = -90;
}
else if (SINUS == 0)
{
angle = 0;
}
else if (SINUS >= 1)
{
angle = 90;
}
else
{
if (SINUS < 0)
{
sinusPositive = -SINUS;
}
else
{
sinusPositive = SINUS;
}

while (quickSearch == false)
{
alpha = angle * 0.0174532925199432;

alpha2 = alpha * alpha;
alpha3 = alpha2 * alpha;
alpha5 = alpha2 * alpha3;

sinus = alpha - (alpha3 / 6.0) + (alpha5 / 120.0) - ((alpha2 * alpha5) / 5040.0);

if (sinus < sinusPositive && incrementAngle >= 1)
{
anglePrevious = angle;
angle += incrementAngle;
}
else if (sinus < sinusPositive && incrementAngle < 1 && error < 9)
{
anglePrevious = angle;
angle += incrementAngle;

error++;
}
else if (sinus == sinusPositive || decimal == 4 + 1)
{
quickSearch = true;
}
else
{
incrementAngle /= 10;
angle = anglePrevious + incrementAngle;

decimal++;
error = 0;
}

if (angle > 90.0001)
{
angle = 89.9999;
quickSearch = true;
}
}

if (SINUS < 0)
{
angle = -angle;
}
}

return angle;
}


Fonction arccos :
float arccos (const float COSINUS)
{
float angle = 0;
float anglePrevious = 0;
float cosinus = 0;
float cosinusPositive = 0;
float alpha = 0;
float alpha2 = 0;
float alpha4 = 0;
float incrementAngle = 10;
unsigned char decimal = 0;
unsigned char error = 0;
bool quickSearch = false;

if (COSINUS <= -1)
{
angle = 180;
}
else if (COSINUS == 0)
{
angle = 90;
}
else if (COSINUS >= 1)
{
angle = 0;
}
else
{
if (COSINUS < 0)
{
cosinusPositive = -COSINUS;
}
else
{
cosinusPositive = COSINUS;
}

while (quickSearch == false)
{
alpha = angle * 0.0174532925199432;

alpha2 = alpha * alpha;
alpha4 = alpha2 * alpha2;

cosinus = 1.0 - ((alpha2 / 2.0) - (alpha4 / 24.0) + ((alpha2 * alpha4) / 720.0) - ((alpha4 * alpha4) / 40320.0));

if (cosinus > cosinusPositive && incrementAngle >= 1)
{
anglePrevious = angle;
angle += incrementAngle;
}
else if (cosinus > cosinusPositive && incrementAngle < 1 && error < 9)
{
anglePrevious = angle;
angle += incrementAngle;

error++;
}
else if (cosinus == cosinusPositive || decimal == 4 + 1)
{
quickSearch = true;
}
else
{
incrementAngle /= 10;
angle = anglePrevious + incrementAngle;

decimal++;
error = 0;
}

if (angle > 90.0001)
{
angle = 89.9999;
quickSearch = true;
}
}

if (COSINUS < 0)
{
angle = 180.0 - angle;
}
}

return angle;
}


Fonction arctan :
float arctan (const float TANGENT)
{
float angle = 0;
float anglePrevious = 0;
float sinus = 0;
float cosinus = 0;
float tangent = 0;
float tangentPositive = 0;
float alpha = 0;
float alpha2 = 0;
float alpha3 = 0;
float alpha4 = 0;
float alpha5 = 0;
float incrementAngle = 10;
unsigned char decimal = 0;
unsigned char error = 0;
bool quickSearch = false;

if (TANGENT <= -9999999999999999)
{
angle = -90;
}
else if (TANGENT == -1)
{
angle = -45;
}
else if (TANGENT == 0)
{
angle = 0;
}
else if (TANGENT == 1)
{
angle = 45;
}
else if (TANGENT >= 9999999999999999)
{
angle = 90;
}
else
{
if (TANGENT < 0)
{
tangentPositive = -TANGENT;
}
else
{
tangentPositive = TANGENT;
}

while (quickSearch == false)
{
alpha = angle * 0.0174532925199432;

alpha2 = alpha * alpha;
alpha3 = alpha2 * alpha;
alpha4 = alpha2 * alpha2;
alpha5 = alpha2 * alpha3;

sinus = alpha - (alpha3 / 6.0) + (alpha5 / 120.0) - ((alpha2 * alpha5) / 5040.0);
cosinus = 1.0 - ((alpha2 / 2.0) - (alpha4 / 24.0) + ((alpha2 * alpha4) / 720.0) - ((alpha4 * alpha4) / 40320.0));
tangent = sinus / cosinus;

if (tangent < tangentPositive && incrementAngle >= 1)
{
anglePrevious = angle;
angle += incrementAngle;
}
else if (tangent < tangentPositive && incrementAngle < 1 && error < 9)
{
anglePrevious = angle;
angle += incrementAngle;

error++;
}
else if (tangent == tangentPositive || decimal == 4 + 1)
{
quickSearch = true;
}
else
{
incrementAngle /= 10;
angle = anglePrevious + incrementAngle;

decimal++;
error = 0;
}

if (angle > 90.0001)
{
angle = 89.9999;
quickSearch = true;
}
}

if (TANGENT < 0)
{
angle = -angle;
}
}

return angle;
}


Fonction arctan2 :
float arctan2 (const float X, const float Y)
{
const float TANGENT = Y / X;
float angle = 0;
float anglePrevious = 0;
float sinus = 0;
float cosinus = 0;
float tangent = 0;
float tangentPositive = 0;
float alpha = 0;
float alpha2 = 0;
float alpha3 = 0;
float alpha4 = 0;
float alpha5 = 0;
float incrementAngle = 10;
unsigned char decimal = 0;
unsigned char error = 0;
bool quickSearch = false;

if (TANGENT <= -9999999999999999)
{
angle = -90;
}
else if (TANGENT == -1)
{
angle = -45;
}
else if (TANGENT == 0)
{
angle = 0;
}
else if (TANGENT == 1)
{
angle = 45;
}
else if (TANGENT >= 9999999999999999)
{
angle = 90;
}
else
{
if (TANGENT < 0)
{
tangentPositive = -TANGENT;
}
else
{
tangentPositive = TANGENT;
}

while (quickSearch == false)
{
alpha = angle * 0.0174532925199432;

alpha2 = alpha * alpha;
alpha3 = alpha2 * alpha;
alpha4 = alpha2 * alpha2;
alpha5 = alpha2 * alpha3;

sinus = alpha - (alpha3 / 6.0) + (alpha5 / 120.0) - ((alpha2 * alpha5) / 5040.0);
cosinus = 1.0 - ((alpha2 / 2.0) - (alpha4 / 24.0) + ((alpha2 * alpha4) / 720.0) - ((alpha4 * alpha4) / 40320.0));
tangent = sinus / cosinus;

if (tangent < tangentPositive && incrementAngle >= 1)
{
anglePrevious = angle;
angle += incrementAngle;
}
else if (tangent < tangentPositive && incrementAngle < 1 && error < 9)
{
anglePrevious = angle;
angle += incrementAngle;

error++;
}
else if (tangent == tangentPositive || decimal == 4 + 1)
{
quickSearch = true;
}
else
{
incrementAngle /= 10;
angle = anglePrevious + incrementAngle;

decimal++;
error = 0;
}

if (angle > 90.0001)
{
angle = 89.9999;
quickSearch = true;
}
}

if (TANGENT < 0)
{
angle = -angle;
}
}

if (X < 0)
{
if (Y >= 0)
{
angle += 180;
}
else
{
angle -= 180;
}
}

return angle;
}





Exemples pour se servir des fonctions

Arrondir des nombres décimaux :

Des calculs complexes en virgule flottante (float), comprenez en nombre décimaux, sont parfois nécessaires afin de conserver la précision tout au long des opérations arithmétiques. Mais la finalité de ces opérations se retrouveront souvent dans un but de faire fonctionner des systèmes prenant en entrée uniquement des nombres entiers. Il est donc nécessaire d'arrondir le résultat en toute fin du calcul.

Exemple pour arrondir un nombre décimal à  l'entier inférieur :
int main()
{
floor (14.6);
//la fonction retourne la valeur 14

return 0;
}


Dans l'exemple ci-dessus, la fonction statique floor est appelée, elle prend en paramètre 14.6, le nombre décimal à  arrondir à  l'entier inférieur, et retourne (dans ce cas de figure) le nombre entier 14.

Exemple pour arrondir un nombre décimal à  l'entier le plus proche :
int main()
{
round (23.7);
//la fonction retourne la valeur 24

return 0;
}


Dans cet exemple la fonction statique round est appelée, elle prend en paramètre 23.7, le nombre décimal à  arrondir à  l'entier le plus proche, et retourne le nombre entier 24.

Exemple pour arrondir un nombre décimal à  l'entier supérieur :
int main()
{
ceil (5.12);
//la fonction retourne la valeur 6

return 0;
}


Ici la fonction statique ceil est appelée, elle prend en paramètre 5.12, le nombre décimal à  arrondir à  l'entier supérieur, et retourne le nombre entier 6.



Créer des interpolations de courbes :

Il est très simple avec les fonctions de courbes que je propose de changer des valeurs d'échelle, d'interpoler des courbes vers d'autres valeurs, tout en ajoutant une non linéarité afin d'adoucir ou de rendre plus vif l'évolution des courbes ainsi créées. Il est également possible de créer des interpolations dissymétriques autour d'un centre arbitraire, mettant en jeu de part et d'autre deux types d'interpolations différentes (linéaires et non linéaires positives et négatives).

Exemple pour créer une interpolation linéaire d'une courbe :
int main()
{
curve (-25, 50, 100, 1, 10, 0);
//la fonction retourne la valeur 6.4

return 0;
}


Dans l'exemple ci-dessus, la fonction statique curve est appelée prenant plusieurs paramètres :
- Le 1er paramètre -25 est le point initial de la courbe.
- Le 2ème paramètre 50 est le point courant de la courbe.
- Le 3ème paramètre 100 est le point final de la courbe.
- Le 4ème paramètre 1 est le point initial de l'interpolation souhaitée.
- Le 5ème paramètre 10 est le point final de l'interpolation souhaitée.
- Le 6ème paramètre 0 défini le type d'interpolation (0 = linéaire) à  partir du point initial vers le point final.

Le résultat du calcul est 6.4.

À noter que les valeurs indiquées en paramètre peuvent indifféremment être positives ou négatives et inférieures ou supérieures les unes par rapport aux autres, la fonction curve est prévue à  cet effet.

Exemple pour créer une interpolation non linéaire d'une courbe :
int main()
{
curve (-25, 50, 100, 1, 10, 40);
//la fonction retourne la valeur ≈ 1.317 (valeur arrondie)

return 0;
}


L'exemple est identique au précédent, sauf le 6ème paramètre 40 (différent de 0 donc non-linéaire) qui permet une interpolation non linéaire positive, plus ce nombre est élevé, plus la non linéarité est prononcée. Un nombre négatif produit une non linéarité négative, c'est-à -dire non pas une interpolation qui évolue doucement proche du point initial de la courbe, mais plutôt évoluant rapidement proche du point initial pour terminer plus douce à  l'approche du point final.

Le résultat du calcul est maintenant ≈ 1.317 (valeur arrondie).

Exemple pour créer une interpolation linéaire dissymétrique d'une courbe :
int main()
{
wurve (0, 50, 70, 0, 9, 10, 0, 0);
//la fonction retourne la valeur ≈ 9.428 (valeur arrondie)

return 0;
}


Dans l'exemple ci-dessus la fonction statique wurve est appelée, voici le détail des paramètres (similaires à  la fonction statique curve) :
- Le 1er paramètre 0 est le point initial de la courbe.
- Le 2ème paramètre 50 est le point courant de la courbe.
- Le 3ème paramètre 70 est le point final de la courbe.
- Le 4ème paramètre 0 est le point initial de l'interpolation souhaitée.
- Le 5ème paramètre 9 est le point central de l'interpolation souhaitée.
- Le 6ème paramètre 10 est le point final de l'interpolation souhaitée.
- Le 7ème paramètre 0 défini le type d'interpolation (0 = linéaire) à  partir du point central vers le point initial.
- Le 8ème paramètre 0 défini le type d'interpolation (0 = linéaire) à  partir du point central vers le point final.

Le résultat du calcul est ≈ 9.428 (valeur arrondie).

À l'instar de la fonction curve, les valeurs indiquées en paramètre avec la fonction wurve peuvent indifféremment être positives ou négatives et inférieures ou supérieures les unes par rapport aux autres.

Exemple pour créer une interpolation double non linéaire centrée d'une courbe :
int main()
{
wurve (0, 473, 1023, 1000, 1500, 2000, 20, 20);
//la fonction retourne la valeur ≈ 1498.069 (valeur arrondie)

return 0;
}


Ci-dessus la fonction statique wurve prend en entrée la valeur d'un potentiomètre pouvant varier de 0 à  1023, c'est la courbe à  interpoler, les valeurs d'interpolation vont de 1000 à  2000 en passant par un centre à  1500, ce centre sert à  créer une double non linéarité centrée sur 1500 ayant des valeurs de 20 (non-linéaire) de part et d'autre de ce point central (ou neutre).

Le résultat du calcul est ≈ 1498.069 (valeur arrondie).

Cette simple expression pourrait servir à  transposer un ordre analogique via un potentiomètre (0 à  1023) vers un signal PWM (pouvant varier de 1000 à  2000 microsecondes) dans le but d'asservir un servo-moteur.

Beaucoup de mes projets utilisent les fonctions de courbes, car elles permettent de transposer facilement des valeurs d'un domaine vers un autre, sans pour autant compliquer la programmation (une ligne de programme est utilisée soit un seul appel de fonction et quelques paramètres).



Cadrer une valeur dans un intervalle :

Il peut être utile de solliciter une fonction dédiée lorsque nous souhaitons qu'une valeur ne sorte pas d'un certain intervalle, sans être obligé de rajouter les conditions logiques nécessaires à  cette fonctionnalité dans notre programme (si inférieur ou égal à , si supérieur ou égal à , etc...), ce qui permet de diminuer le nombre d'instructions visibles et d'augmenter la lisibilité du code source.

Exemple pour cadrer une valeur dans un intervalle :
int main()
{
range (-10, 23, 10);
//la fonction retourne une valeur qui ne sortira jamais de l'intervalle -10 à  10

return 0;
}


Dans l'exemple ci-dessus, la fonction statique range limite l'intervalle que peut prendre le nombre 23, ceci dans un cadre -10 à  10. La fonction retourne alors le nombre 10.

Les valeurs indiquées en paramètre peuvent indifféremment être positives ou négatives et inférieures ou supérieures les unes par rapport aux autres, la fonction range est implémentée à  cet effet.



Calculer la moyenne de deux valeurs :

De même que la fonction présentée ci-dessus, une fonction pour trouver la moyenne de deux nombres (ou centre) semble facultative, néanmoins elle reste bien pratique !

Exemple pour calculer la moyenne de deux valeurs :
int main()
{
center (125, 85.3);
//la fonction retourne la valeur 105.15

return 0;
}


Dans l'exemple ci-dessus la fonction statique center prend en paramètre les nombres 125 et 85.3, elle retourne donc la moyenne de ces deux nombre, soit 105.15.

L'ordre des nombres indiqués en paramètre à  la fonction statique center peuvent être permutés indifféremment.



Calculer la puissance d'un nombre :

La puissance d'un nombre est le résultat de la multiplication répétée (via un exposant) de ce nombre avec lui même.

Exemple pour calculer la puissance d'un nombre :
int main()
{
pow (5, 4);
//la fonction retourne la valeur 625

return 0;
}


Ici le nombre 5 représente le nombre à  multiplier avec lui-même, 4 est l'exposant, soit le calcul 5 x 5 x 5 x 5 = 625.

Le nombre à  multiplier avec lui même ainsi que l'exposant peuvent être positifs, nuls, ou négatifs.



Calculer la racine carrée d'un nombre :

Le résultat de la racine carrée d'un nombre, est un nombre qui, multiplié par lui-même, donne le radicande (soit le nombre entré en paramètre à  la fonction).

Exemple pour calculer la racine carrée d'un nombre :
int main()
{
sqrt (25);
//la fonction retourne la valeur 5

return 0;
}


Ci-dessus le nombre 25 est le résultat du nombre 5 multiplié par lui-même (5 x 5 = 25), la fonction retourne donc le nombre 5.



Calculer la factorielle d'un nombre :

La factorielle d'un nombre est le produit des nombres entiers strictement positifs inférieurs ou égaux à  ce nombre. Cet algèbre permet d'effectuer des approches du nombre Pi, de faire converger des équations pour obtenir le sinus, le cosinus, etc...

Exemple pour calculer la factorielle d'un nombre :
int main()
{
fact (7);
//la fonction retourne la valeur 5040

return 0;
}


Dans l'exemple ci-dessus la factorielle du nombre 7 entré en paramètre donne le résultat 5040, car 1 x 2 x 3 x 4 x 5 x 6 x 7 = 5040.

Par convention la factorielle du nombre 0 est 1.



Les fonctions sinus, cosinus, et tangente :

Les fonctions trigonométriques élémentaires comme sinus, cosinus, ou encore tangente s'avèrent utiles dans le domaine des automates programmables afin d'obtenir la position angulaire d'un robot, calculer la trajectoire d'un objet à  l'aide d'un gyroscope, etc...

Attention, mes fonctions trigonométriques sin (sinus), cos (cosinus), et tan (tangente) prennent en entrée un angle en degrés (et non pas en radians).

Exemple pour calculer le sinus d'un angle :
int main()
{
sin (30);
//la fonction retourne la valeur 0.5

return 0;
}


Dans cet exemple le sinus de l'angle 30 degrés est 0.5.

Exemple pour calculer le cosinus d'un angle :
int main()
{
cos (45);
//la fonction retourne la valeur ≈ 0.707 (valeur arrondie)

return 0;
}


Dans l'exemple ci-dessus, le cosinus de l'angle 45 degrés est ≈ 0.707 (valeur arrondie).

Exemple pour calculer la tangente d'un angle :
int main()
{
tan (45);
//la fonction retourne la valeur 1

return 0;
}


Ci-dessus la tangente de l'angle 45 degrés est 1.



Les fonctions réciproques arc sinus, arc cosinus, arc tangente, et arc tangente 2 :

En complément des fonctions sinus, cosinus, et tangente, il est fort utile de disposer des fonctions réciproques comme arc sinus, arc cosinus, arc tangente, et arc tangente 2.

Attention, mes fonctions trigonométriques arcsin (arc sinus), arccos (arc cosinus), arctan (arc tangente), et arctan2 (arc tangente à  partir de deux arguments x et y) retournent en sortie un angle en degrés (et non pas en radians).

Exemple pour trouver l'angle à  partir d'un sinus :
int main()
{
arcsin (0.5);
//la fonction retourne la valeur 30

return 0;
}


Dans l'exemple ci-dessus, un sinus de 0.5 correspond à  un angle de 30 degrés.

Exemple pour trouver l'angle à  partir d'un cosinus :
int main()
{
arccos (0.707);
//la fonction retourne la valeur ≈ 45.008 (valeur arrondie)

return 0;
}


Avec la fonction statique arccos, on trouve qu'un cosinus de 0.707 correspond à  un angle de ≈ 45.008 degrés (valeur arrondie).

Exemple pour trouver l'angle à  partir d'une tangente :
int main()
{
arctan (1);
//la fonction retourne la valeur 45

return 0;
}


Une tangente de 1 correspond à  un angle de 45 degrés.

Exemple pour trouver l'angle à  partir de la tangente de deux arguments x et y (ou fonction circulaire réciproque à  quatre cadrans) :
int main()
{
arctan2 (0.5, 0.5);
//la fonction retourne la valeur 45

return 0;
}


Dans l'exemple ci-dessus, une tangente à  partir de deux arguments x égal à  0.5 et y égal à  0.5 correspond à  un angle de 45 degrés.



Récapitulatif des paramètres des fonctions :

static signed long floor (const float VALUE);
static signed long round (const float VALUE);
static signed long ceil (const float VALUE);
static float curve (const float POSITION_START, const float POSITION_CURRENT, const float POSITION_END, const float INTERPOLATION_START, const float INTERPOLATION_END, const float CURVE);
static float wurve (const float POSITION_START, const float POSITION_CURRENT, const float POSITION_END, const float INTERPOLATION_START, const float INTERPOLATION_CENTER, const float INTERPOLATION_END, const float CURVE_START, const float CURVE_END);
static float range (const float RANGE_START, const float VALUE_CURRENT, const float RANGE_END);
static float center (const float VALUE_START, const float VALUE_END);
static float pow (const float NUMBER, const unsigned long EXPONENT);
static float sqrt (const float RADICAND);
static unsigned long long fact (const unsigned long INTEGER);
static float sin (const float ANGLE);
static float cos (const float ANGLE);
static float tan (const float ANGLE);
static float arcsin (const float SINUS);
static float arccos (const float COSINUS);
static float arctan (const float TANGENT);
static float arctan2 (const float X, const float Y);




Les fonctions ci-dessus simplifient grandement la mise en oeuvre de nombreuses applications, vous pouvez combiner les fonctions entres-elles et obtenir des résultats étonnants de complexité !

Si vos applications requièrent des fonctions mathématiques qui ne sont pas présentes ici, libre à  vous d'en ajouter si besoin ;)

papyblue

Bonjour Sylvain,

Merci pour ce partage, un plus serait d'y associer un nombre de cycles d'horloge nécessaires pour chaque fonction. Cette connaissance peut être utile pour des applications critiques.

PB

loulou31

Bonjour et bonne année à  tous,

On ne peut associer simplement un nombre de cycles d'horloge a  une une fonction en C. En effet ça dépend du compilateur, de la cible ( processeur qui va exécuter le code) et aussi du type de variable ( entier 16 32 bits, flottant....) .

Jean-Louis

papyblue

Bonjour Jean-Louis et mes meilleurs voeux pour 2021,

Votre remarque est juste mais ma réflexion était dans le cadre où on utilise un microprocesseur peu puissant (genre arduino) et que l'on cherche à  optimiser le temps d'exécution. Quel intérêt à  réécrire une bibliothèque s'il n'y a pas de gain quelque part : place ou vitesse ? D'ailleurs le passage par des flottants n'est sans doute pas la meilleure solution quand il n'y a pas nativement de coprocesseur mathématique et que le résultat final doit être un entier. Personnellement, je préfère utiliser le calcul en virgule fixe et des méthodes tabulées ou des développements limités.
Pour revenir sur ma remarque, un temps d'exécution sur un arduino UNO pourrait être une solution. Avant d'embarquer dans son code une fonction, il est toujours bon d'en connaitre les performances.

Cordialement.

sylvainmahe

#4
Citation"Quel intérêt à  réécrire une bibliothèque s'il n'y a pas de gain quelque part : place ou vitesse ? D'ailleurs le passage par des flottants n'est sans doute pas la meilleure solution quand il n'y a pas nativement de coprocesseur mathématique et que le résultat final doit être un entier."

Bonjour à  vous, ma réponse est la suivante :

Le gain peut être de plusieurs nature, soit :
- L'espace mémoire.
- La vitesse d'exécution.
- La résolution du calcul.
- La précision du calcul.
- La pédagogie, l'apprentissage, le partage.
- La conception logique et arithmétique.
- La possibilité de modifier nos propres fonctions pour qu'elles soient davantage adaptées aux applications pratiques.

Les microcontrôleurs dans lesquels j'ai besoin de ces calculs sont :
ATmega48P
ATmega88P
ATmega168P
ATmega328P
ATmega164P
ATmega324P
ATmega644P
ATmega1284P

sylvainmahe

#5
Citation de: w1200 le Avril 14, 2023, 12:58:55 PM
Un adepte de l'ATmega.

Adepte oui certainement au sens étymologique, mais pas totalement :

CitationUn adepte (du latin adeptus : « qui a acquis ») est à  l'origine celui qui a atteint le « Grand oeuvre » de l'alchimie ou adeptat[1]. C'est aussi par extension celui qui touche au but d'un enseignement secret élitiste, d'une science. On parle également, par généralisation, d'adepte pour une personne ayant adopté une pratique, spirituelle, ou autre, ou simplement un usage nouveau

En effet, il n'y a pas de secret élitiste dans ce que je propose, c'est plutôt la formule "gratuit, libre de droits d'auteur, et à  sources ouvertes et modifiables".

Ces petits ATmega répondent toujours entièrement (vitesse d'exécution, taille mémoire, consommation électrique, compacité pour l'embarqué, etc...) aux contraintes techniques et physiques imposées par mes projets et les applications associées. Ayant développé un outil pour cible huit ATmega, cela permet de réaliser des projets très complexes assez rapidement et efficacement.

sylvainmahe

#6
Citation de: w1200 le Avril 16, 2023, 12:56:22 AM
Citation
Personne pratiquant un sport ou une activité, fervent.

Ceci n'est pas l'étymologie, et nous comprenons davantage à  quoi nous avons affaire lorsque nous regardons l'étymologie.

Un exemple avec le mot "écologie", eco signifiant "habitat" "maison", et "logie" signifiant "le discours" "la science de". On comprend à  ce moment que l'écologie pose le discours et l'interrogation de comment habiter cette planète (intelligemment)...


Pour le sujet initial, quelle pourrait être votre contribution ? Une aide : à  l'avenir des fonctions de logarithme, d'exponentiel, et de constante d'Euler seront intégrés.

Il est possible que j'apporte des fonctions de calcul sur les couleurs également.

sylvainmahe

Citation de: w1200 le Avril 16, 2023, 11:43:03 AM
Je ne vois pas quelle contribution apporter à  votre projet, vous semblez avoir beaucoup de temps et être très avancé.

Cela pourrait être un calcul que vous avez déjà  utilisé dans vos projets, une fonction mathématique que vous utilisez mais que vous ne voyez pas dans mon énoncé, ou une idée simplement.

sylvainmahe

#8
Citation de: w1200 le Avril 16, 2023, 10:05:31 PM
Citation de: sylvainmahe le Avril 16, 2023, 08:21:19 PM
Citation de: w1200 le Avril 16, 2023, 11:43:03 AM
Je ne vois pas quelle contribution apporter à  votre projet, vous semblez avoir beaucoup de temps et être très avancé.

Cela pourrait être un calcul que vous avez déjà  utilisé dans vos projets, une fonction mathématique que vous utilisez mais que vous ne voyez pas dans mon énoncé, ou une idée simplement.

Pas mon genre de projets.

Je ne comprends donc pas votre intervention décidément si :
- Vos genres de projets ne sont pas ceux-ci.
et si :
- Vous ne pensez ou pouvez pas contribuer.


Quoiqu'il en soit, un livre imprimé "Programmer sans <math.h>" existe afin de partager les fonctions et pouvoir en discuter autrement :

sylvainmahe

#9
Citation de: w1200 le Avril 17, 2023, 01:21:42 PM
Quel est l'ISBN?

Bonjour à  vous, il n'y a pas d'ISBN car c'est simplement du partage local et dans la gratuité avec les personnes intéressées.

Par exemple récemment j'ai donné un livre "La documentation du programme MODULE" à  un ami. Ce livre étant la redondance papier imprimé de cette section : http://sylvainmahe.site/index.html#documentationGpioRead

Si à  l'avenir je partage différemment je pourrais demander un ISBN car je connais bien la procédure. Mais pour l'instant je n'en vois pas l'utilité pour mes livres partagés en local.

sylvainmahe

Citation de: w1200 le Avril 18, 2023, 09:20:11 PM
Dans votre région vous n'êtes pas tenu de demander un ISBN pour le dépôt légal?

Bonjour à  vous, non je n'ai pas d'obligation.

àŠtes-vous intéressé pour proposer des fonctions mathématiques et les partager ?

sylvainmahe

Citation de: w1200 le Avril 19, 2023, 01:01:35 PM
Citation de: sylvainmahe le Avril 19, 2023, 07:58:30 AM
Citation de: w1200 le Avril 18, 2023, 09:20:11 PM
Dans votre région vous n'êtes pas tenu de demander un ISBN pour le dépôt légal?

Bonjour à  vous, non je n'ai pas d'obligation.

Ici c'est obligatoire.

Citation de: sylvainmahe le Avril 19, 2023, 07:58:30 AM
àŠtes-vous intéressé pour proposer des fonctions mathématiques et les partager ?

Je ne suis pas mathématicien.

L'ISBN n'est pas obligatoire lorsqu'on donne un livre à  notre cercle de proches (famille, amis, ...), et c'est mon cas. Il n'est donc pas obligatoire.

Qu'en aux mathématiques, il n'est pas requis d'être mathématicien de profession pour effectuer des mathématiques, proposer des fonctions, proposer des algorithmes, les partager et en discuter.

sylvainmahe

#12
Citation de: w1200 le Avril 19, 2023, 07:09:41 PM
Citation de: sylvainmahe le Avril 19, 2023, 07:00:16 PM
Citation de: w1200 le Avril 19, 2023, 01:01:35 PM
Citation de: sylvainmahe le Avril 19, 2023, 07:58:30 AM
Citation de: w1200 le Avril 18, 2023, 09:20:11 PM
Dans votre région vous n'êtes pas tenu de demander un ISBN pour le dépôt légal?

Bonjour à  vous, non je n'ai pas d'obligation.

Ici c'est obligatoire.

Citation de: sylvainmahe le Avril 19, 2023, 07:58:30 AM
àŠtes-vous intéressé pour proposer des fonctions mathématiques et les partager ?

Je ne suis pas mathématicien.

L'ISBN n'est pas obligatoire lorsqu'on donne un livre à  notre cercle de proches (famille, amis, ...), et c'est mon cas. Il n'est donc pas obligatoire.

Qu'en aux mathématiques, il n'est pas requis d'être mathématicien de profession pour effectuer des mathématiques, proposer des fonctions, proposer des algorithmes, les partager et en discuter.

Ici il faut un dépôt légal au BAnQ et pour ce faire un ISBN est requis.

Mon cercle proche est français et en France donc je n'ai pas besoin d'ISBN comme indiqué.

Ok sujet initial : je vous propose un exemple d'application à  la fonction arctan2. Cet exemple va vous permettre de calculer le tangage et le roulis à  partir de trois accéléromètres montés en x y z.

Suivant le mode indiqué par la constante "MODE_AERO_PITCH" et "MODE_AERO_ROLL", le tangage et/ou le roulis vont pouvoir débattre soit de -90° à  +90°, soit de -180° à  +180° angulaires. Cela signifie qu'en mode aero pitch = vrai, un aéronef en vol dos en piqué à  45° (par exemple) peut se redresser avec un 45° piqueur et un 180° au roulis, ce qui peut éviter le crash.

Ci-après la conversion des accélérations x y z en tangage et roulis en degrés angulaires à  l'aide de la fonction arctan2 :
Citationfloat pitch = 0;
float roll = 0;
const bool MODE_AERO_PITCH = true;
const bool MODE_AERO_ROLL = false;

while (true)
{
gyroscope.readTranslation();

if (gyroscope.tz < 0)
{
if (gyroscope.tx < 0)
{
if (MODE_AERO_PITCH == false)
{
pitch = Math::arctan2 (gyroscope.tz + gyroscope.tx, gyroscope.ty);
}
else
{
pitch = Math::arctan2 (-gyroscope.tz - gyroscope.tx, gyroscope.ty);
}
}
else
{
if (MODE_AERO_PITCH == false)
{
pitch = Math::arctan2 (gyroscope.tz - gyroscope.tx, gyroscope.ty);
}
else
{
pitch = Math::arctan2 (-gyroscope.tz + gyroscope.tx, gyroscope.ty);
}
}
}
else
{
if (gyroscope.tx < 0)
{
pitch = Math::arctan2 (gyroscope.tz - gyroscope.tx, gyroscope.ty);
}
else
{
pitch = Math::arctan2 (gyroscope.tz + gyroscope.tx, gyroscope.ty);
}
}

if (gyroscope.tz < 0)
{
if (gyroscope.ty < 0)
{
if (MODE_AERO_ROLL == false)
{
roll = -Math::arctan2 (gyroscope.tz + gyroscope.ty, gyroscope.tx);
}
else
{
roll = -Math::arctan2 (-gyroscope.tz - gyroscope.ty, gyroscope.tx);
}
}
else
{
if (MODE_AERO_ROLL == false)
{
roll = -Math::arctan2 (gyroscope.tz - gyroscope.ty, gyroscope.tx);
}
else
{
roll = -Math::arctan2 (-gyroscope.tz + gyroscope.ty, gyroscope.tx);
}
}
}
else
{
if (gyroscope.ty < 0)
{
roll = -Math::arctan2 (gyroscope.tz - gyroscope.ty, gyroscope.tx);
}
else
{
roll = -Math::arctan2 (gyroscope.tz + gyroscope.ty, gyroscope.tx);
}
}

Désolé pour l'indentation qui n'est plus présente.

Ces calculs vous permettent de créer un horizon artificiel, et donc peuvent trouver une application notamment dans la stabilisation d'un aéronef, ou d'un robot terrestre. D'autres applications sont possibles.

sylvainmahe

#13
Citation de: w1200 le Avril 19, 2023, 08:03:20 PM
Citation de: sylvainmahe le Avril 19, 2023, 07:54:29 PM

Mon cercle proche est français et en France donc je n'ai pas besoin d'ISBN comme indiqué, merci.


Si l'imprimeur ou l'éditeur n'est pas situé en France.

Il l'est, d'autant que je suis mon propre éditeur.

Avez vous une contribution à  apporter à  ce sujet sur le thème des mathématiques ? Merci.

sylvainmahe

Citation de: w1200 le Avril 19, 2023, 08:23:45 PM
Citation de: sylvainmahe le Avril 19, 2023, 08:15:22 PM
Citation de: w1200 le Avril 19, 2023, 08:03:20 PM
Citation de: sylvainmahe le Avril 19, 2023, 07:54:29 PM

Mon cercle proche est français et en France donc je n'ai pas besoin d'ISBN comme indiqué, merci.


Si l'imprimeur ou l'éditeur n'est pas situé en France.

Il l'est, d'autant que je suis mon propre éditeur.

Si il est en France il est tenu au dépôt légal.

Citation de: sylvainmahe le Avril 19, 2023, 08:15:22 PM

Avez vous une contribution à  apporter à  ce sujet sur le thème des mathématiques ? Merci.


Pas vraiment n'étant pas mathématicien.

Je réitère que je n'ai pas l'obligation du dépôt légal :
https://www.bnf.fr/fr/quest-ce-que-le-depot-legal

Je réitère, avez-vous une contribution à  ce sujet ? Il n'est nullement besoin d'être professionnel pour proposer des choses, en l'occurrence ici des algorithmes mathématiques.