/** * @file ALGO_AlgorithmBase_ATY.c * * @param Project ALGO_Algorithm_ATY_LIB * * @author ATY * * @copyright * - Copyright 2017 - 2026 MZ-ATY * - This code follows: * - MZ-ATY Various Contents Joint Statement - * * https://mengze.top/MZ-ATY_VCJS * - CC 4.0 BY-NC-SA - * * https://creativecommons.org/licenses/by-nc-sa/4.0/ * - Your use will be deemed to have accepted the terms of this statement. * * @brief functions of base algorithm * * @version * - 1_01_220601 > ATY * -# Preliminary version, first Release * - 1_02_251124 > ATY * -# add and test * @todo long support ******************************************************************************** */ #ifndef __ALGO_AlgorithmBase_ATY_C #define __ALGO_AlgorithmBase_ATY_C #include "ALGO_AlgorithmBase_ATY.h" #define ALGO_AlgorithmBase_ATY_TAG "\r\n[ALGO_AlgorithmBase_ATY] " /******************************* For user *************************************/ /******************************************************************************/ /* Bit Inversion **************************************************************/ /* Easy way to implement Invert ***********************************************/ /** * @brief Invert buf with uint8 size(LSB <-> MSB) * @param genBuf Generate buf * @param srcBuf Input source buf */ void ALGO_InvertUint8_Group(uint8_t* genBuf, uint8_t* srcBuf){ uint8_t i = 0; uint8_t temp_uint8 = 0; for(i = 0; i < 8; i++){ if((*srcBuf) & (1 << i)) temp_uint8 |= 1 << (7 - i); } *genBuf = temp_uint8; } /** * @brief Invert buf with uint16 size(LSB <-> MSB) * @param genBuf Generate buf * @param srcBuf Input source buf */ void ALGO_InvertUint16_Group(uint16_t* genBuf, uint16_t* srcBuf){ uint8_t i = 0; uint16_t temp_uint16 = 0; for(i = 0; i < 16; i++){ if((*srcBuf) & (1 << i)) temp_uint16 |= 1 << (15 - i); } *genBuf = temp_uint16; } /** * @brief Invert buf with uint32 size(LSB <-> MSB) * @param genBuf Generate buf * @param srcBuf Input source buf */ void ALGO_InvertUint32_Group(uint32_t* genBuf, uint32_t* srcBuf){ uint8_t i = 0; uint32_t temp_uint32 = 0; for(i = 0; i < 32; i++){ if((*srcBuf) & (1 << i)) temp_uint32 |= 1 << (31 - i); } *genBuf = temp_uint32; } /** * @brief Invert buf with n size(LSB <-> MSB) * @param genBuf Generate buf * @param srcBuf Input source buf * @param len Data length */ void ALGO_InvertBitsN_Group(uint32_t* genBuf, uint32_t* srcBuf, uint8_t len){ uint8_t i = 0; uint32_t temp_uint32 = 0; for(i = 0; i < len; i++){ if((*srcBuf) & (1 << i)) temp_uint32 |= 1 << (len - 1 - i); } *genBuf = temp_uint32; } /* End of Easy way to implement Invert ****************************************/ /* Math Utilities *************************************************************/ /** * @brief Pow() function in easy way * @param x value to deal * @param n index, >= 0 * @note 17 significant digits */ float ALGO_MATH_POW_EASY(float x, uint8_t n){ float result = 1; while(n--) result *= x; return result; } /** * @brief Pow() function in quick way * @param x value to deal * @param n index, >= 0 */ int ALGO_MATH_POW_QUICK(int x, int n){ float result = 1; while(n){ if(n & 1) result = result * x; x = x * x; n >>= 1; } return result; } /** * @brief Pow() function * @param x value to deal * @param n index */ float ALGO_MATH_POW(float x, int n){ if(n == 0) return 1.0; else if(n < 0) return 1.0 / ALGO_MATH_POW(x, -n); else if(n > 0){ float temp_d = ALGO_MATH_POW(x, n / 2); if((n % 2) == 1) // odd n return x * temp_d * temp_d; else // even n return temp_d * temp_d; } return 0; } /** * @brief Sqrt() function * @param x value to deal */ int ALGO_MATH_SQRT(int x){ int left = 1; int right = x; int result = 0; while(left <= right){ int mid = left + (right - left) / 2; if(mid <= x / mid){ result = mid; left = mid + 1; } else{ right = mid - 1; } } return result; } /** * @brief ln() function * @param x value to deal * @note 17 significant digits */ float ALGO_MATH_LogLn(float x){ // take the first 15+1 terms to estimate const int N = 15; int k, nk; float a, aa, b; a = (x - 1) / (x + 1); aa = a * a; nk = 2 * N + 1; b = 1.0 / nk; for(k = N; k > 0; k--){ nk = nk - 2; b = 1.0 / nk + aa * b; } return 2.0 * a * b; } float ALGO_NumberSuitScop(float valueIn, float scopMin, float scopMax, float step){ uint16_t errCount = 0; while((valueIn < scopMin || valueIn > scopMax) && (uint32_t)step != 0){ errCount++; if(errCount > 60000) return -1; if(valueIn < scopMin) valueIn += step; else if(valueIn > scopMax) valueIn -= step; } return valueIn; } uint16_t ALGO_BinarySearch(const double* arr, uint16_t size, double target){ uint16_t l = 0, r = size; while(l < r){ uint16_t m = l + ((r - l) >> 1); if(arr[m] < target) l = (uint16_t)(m + 1); else r = m; } return (l < size) ? l : size; } float ALGO_Sqrt_NewtonNumber(float x){ float xhalf = 0.5 * x; int i = *(int*)&x; if(!x) return 0; i = 0x5f375a86 - (i >> 1); // beautiful number x = *(float*)&i; x = x * (1.5 - xhalf * x * x); // Newton iteration x = x * (1.5 - xhalf * x * x); // Newton iteration x = x * (1.5 - xhalf * x * x); // Newton iteration return (1 / x); } /* Metrics ********************************************************************/ float ALGO_GetRms(uint16_t currentValue, uint16_t currentNum, float sumValue, uint16_t wholeNum){ float value = sumValue; value += (currentValue * currentValue); if(currentNum >= wholeNum){ value /= currentNum; value = ALGO_Sqrt_NewtonNumber(value); return value; } return 0; } /* RC Filters *****************************************************************/ double ALGO_RC_LpFilter(ALGO_RC_FilterPara_t* rcPara, double val){ rcPara->lVal = ((double)val * rcPara->k + rcPara->lVal * (1 - rcPara->k)); return rcPara->lVal; } double ALGO_RC_HpFilter(ALGO_RC_FilterPara_t* rcPara, double val){ rcPara->lVal = ((double)val * rcPara->k + rcPara->lVal * (1 - rcPara->k)); return -(val - rcPara->lVal); } /* Debug Tests ****************************************************************/ #ifdef __DEBUG_ALGO_AlgorithmBase_ATY void ALGO_Swap_Test(void){ uint32_t a = 0, b = 1; printf_ATY("\r\nALGO_Swap_Test - Before: %d - %d\r\n", a, b); ALGO_SWAP(uint8_t, 0, a, b); printf_ATY("\r\nALGO_Swap_Test - After: %d - %d\r\n", a, b); } void ALGO_Sort_Test(void){ const uint32_t temp_uint32[12] = { 0xffffff14, 0xffffff19, 0xffffff17, 0xffffff12, 0xffffff18, 0xffffff00, 0xffffff11, 0xffffffff, 0xffffff13, 0xffffff15, 0xffffff16, 0xffffff20}; printf_ATY("\r\nALGO_Sort_Test - Before: \r\n"); for(uint8_t i = 0; i < 12; i++) printf_ATY("%x ", temp_uint32[i]); printf_ATY("\r\n"); ALGO_Sort(uint32_t, 0, temp_uint32); printf_ATY("\r\nALGO_Sort_Test - After: \r\n"); for(uint8_t i = 0; i < 12; i++) printf_ATY("%x ", temp_uint32[i]); printf_ATY("\r\n"); } void ALGO_AverageInDelExtremum_Test(void){ const uint32_t temp_uint32g[12] = {14, 19, 17, 12, 18, 0, 11, 1055, 13, 15, 16, 20}; uint32_t temp_uint32; printf_ATY("\r\nALGO_AverageInDelExtremum_Test - Origin: \r\n"); for(uint8_t i = 0; i < 12; i++) printf_ATY("%d ", temp_uint32g[i]); printf_ATY("\r\n"); ALGO_AverageInDelExtremum(uint32_t, 0, temp_uint32g, temp_uint32); printf_ATY("\r\nALGO_AverageInDelExtremum_Test - Result: %d\r\n", temp_uint32); } void ALGO_INVERT_Test(void){ uint32_t TT0 = 0; const uint8_t TT1 = 0xF0; // 0x0F const uint8_t TT2 = 0x12; // 0x48 const uint16_t TT3 = 0xF0E0; // 0x070F const uint16_t TT4 = 0x1234; // 0x2C48 const uint32_t TT5 = 0xF0E0D0C0; // 0x030B070F const uint32_t TT6 = 0x12345678; // 0x1E6A2C48 ALGO_INVERT_BITS(TT1); TT0 = TT1; ALGO_INVERT_BITS(TT2); TT0 = TT2; ALGO_INVERT_BITS(TT3); TT0 = TT3; ALGO_INVERT_BITS(TT4); TT0 = TT4; ALGO_INVERT_BITS(TT5); TT0 = TT5; ALGO_INVERT_BITS(TT6); TT0 = TT6; TT0 = 0; } void ALGO_Test_Whole(void){ printf_ATY("\r\n\r\n"); printf_ATY("------------------\r\n"); printf_ATY("/* - ALGO_TEST -*/\r\n"); ALGO_Swap_Test(); ALGO_Sort_Test(); ALGO_AverageInDelExtremum_Test(); } #endif /* __DEBUG_ALGO_AlgorithmBase_ATY */ #ifdef ALGO_AlgorithmBase_ATY_Test_ATY uint8_t ALGO_AlgorithmBase_ATY_Test_Pass; uint8_t ALGO_AlgorithmBase_ATY_Test_Fail; static int __aty_close_d(double a, double b, double tol){ return (a > b ? (a - b) : (b - a)) <= tol; } static int __aty_equal_u(uint32_t a, uint32_t b){ return a == b; } uint32_t ALGO_AlgorithmBase_ATY_Test(void){ ALGO_AlgorithmBase_ATY_Test_Pass = 0; ALGO_AlgorithmBase_ATY_Test_Fail = 0; printf_ATY_D("%sSTART\r\n", ALGO_AlgorithmBase_ATY_TAG); { int a = -5, b = 7; int abs_a = ALGO_ABS(a); int max_ab = ALGO_MAX(a, b); int min_ab = ALGO_MIN(a, b); int ok1 = __aty_equal_u((uint32_t)abs_a, (uint32_t)5); int ok2 = __aty_equal_u((uint32_t)max_ab, (uint32_t)7); int ok3 = __aty_equal_u((uint32_t)min_ab, (uint32_t)-5); if(ok1) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; if(ok2) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; if(ok3) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" ABS(a) = %d, MAX = %d, MIN = %d, %s\r\n", abs_a, max_ab, min_ab, ((ok1 && ok2 && ok3) ? "PASS" : "FAIL")); } { int okd1 = ALGO_DECCHK('5'); int okd2 = !ALGO_DECCHK('A'); int okh1 = ALGO_HEXCHK('F'); int okh2 = !ALGO_HEXCHK('G'); if(okd1 && okd2) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; if(okh1 && okh2) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" DEC = %d/%d, HEX = %d/%d, %s\r\n", okd1, okd2, okh1, okh2, ((okd1 && okd2 && okh1 && okh2) ? "PASS" : "FAIL")); } { uint16_t c16 = ALGO_COMB16(0x12, 0x34); uint32_t c32 = ALGO_COMB32(0x12, 0x34, 0x56, 0x78); uint8_t l16 = ALGO_UINT16_L(0x1234); uint8_t h16 = ALGO_UINT16_H(0x1234); int okc16 = __aty_equal_u(c16, 0x1234u); int okc32 = __aty_equal_u(c32, 0x12345678u); int oklh = __aty_equal_u((uint32_t)l16, (uint32_t)0x34u) && __aty_equal_u((uint32_t)h16, (uint32_t)0x12u); if(okc16) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; if(okc32) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; if(oklh) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" COMB16 = 0x%x, COMB32 = 0x%x, L = 0x%x, H = 0x%x, %s\r\n", c16, c32, l16, h16, ((okc16 && okc32 && oklh) ? "PASS" : "FAIL")); } { int okb = __aty_equal_u((uint32_t)ALGO_BOOL(5), (uint32_t)1); int okn = __aty_equal_u((uint32_t)ALGO_NOT(0), (uint32_t)1); int oka = __aty_equal_u((uint32_t)ALGO_AND(1, 0), (uint32_t)0); int oko = __aty_equal_u((uint32_t)ALGO_OR(1, 0), (uint32_t)1); if(okb && okn && oka && oko) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" BOOL = %d, NOT = %d, AND = %d, OR = %d, %s\r\n", ALGO_BOOL(5), ALGO_NOT(0), ALGO_AND(1, 0), ALGO_OR(1, 0), ((okb && okn && oka && oko) ? "PASS" : "FAIL")); } { float pe = ALGO_MATH_POW_EASY(2.0f, 10); int pq = ALGO_MATH_POW_QUICK(2, 10); float pn = ALGO_MATH_POW(2.0f, 10); int okpe = __aty_close_d(pe, 1024.0, 1e-5); int okpq = __aty_equal_u((uint32_t)pq, (uint32_t)1024); int okpn = __aty_close_d(pn, 1024.0, 1e-3); if(okpe) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; if(okpq) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; if(okpn) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" POW_EASY = %f, POW_QUICK = %d, POW = %f, %s\r\n", pe, pq, pn, ((okpe && okpq && okpn) ? "PASS" : "FAIL")); } { int s10 = ALGO_MATH_SQRT(10); int s16 = ALGO_MATH_SQRT(16); int oks = __aty_equal_u((uint32_t)s10, (uint32_t)3) && __aty_equal_u((uint32_t)s16, (uint32_t)4); if(oks) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" SQRT(10) = %d, SQRT(16) = %d, %s\r\n", s10, s16, (oks ? "PASS" : "FAIL")); } { float le = ALGO_MATH_LogLn(2.7182818f); int okle = __aty_close_d(le, 1.0, 1e-3); if(okle) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" LN(e) = %f, %s\r\n", le, (okle ? "PASS" : "FAIL")); } { float sn = ALGO_Sqrt_NewtonNumber(9.0f); int oksi = __aty_close_d(sn, 3.0, 1e-3); if(oksi) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" NewtonSqrt(9) = %f, %s\r\n", sn, (oksi ? "PASS" : "FAIL")); } { ALGO_RC_FilterPara_t lp = {0.1, 0.0}; double o1 = ALGO_RC_LpFilter(&lp, 0.0); double o2 = ALGO_RC_LpFilter(&lp, 10.0); double o3 = ALGO_RC_LpFilter(&lp, 10.0); double e2 = 10.0 * 0.1 + 0.0 * 0.9; double e3 = 10.0 * 0.1 + e2 * 0.9; int okrc = __aty_close_d(o1, 0.0, 1e-9) && __aty_close_d(o2, e2, 1e-9) && __aty_close_d(o3, e3, 1e-9); if(okrc) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" LP o1 = %f, o2 = %f, o3 = %f, %s\r\n", o1, o2, o3, (okrc ? "PASS" : "FAIL")); } { ALGO_RC_FilterPara_t hp = {0.1, 0.0}; double h1 = ALGO_RC_HpFilter(&hp, 0.0); double h2 = ALGO_RC_HpFilter(&hp, 10.0); double h3 = ALGO_RC_HpFilter(&hp, 10.0); double e2 = -(10.0 - (10.0 * 0.1 + 0.0 * 0.9)); double e3 = -(10.0 - (10.0 * 0.1 + (10.0 * 0.1 + 0.0 * 0.9) * 0.9)); int okhp = __aty_close_d(h1, 0.0, 1e-9) && __aty_close_d(h2, e2, 1e-9) && __aty_close_d(h3, e3, 1e-9); if(okhp) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" HP h1 = %f, h2 = %f, h3 = %f, %s\r\n", h1, h2, h3, (okhp ? "PASS" : "FAIL")); } { float v1 = ALGO_NumberSuitScop(105.0f, 0.0f, 100.0f, 1.0f); float v2 = ALGO_NumberSuitScop(-5.0f, 0.0f, 100.0f, 1.0f); int okns = __aty_close_d(v1, 100.0, 1e-5) && __aty_close_d(v2, 0.0, 1e-5); if(okns) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" SuitScop v1 = %f, v2 = %f, %s\r\n", v1, v2, (okns ? "PASS" : "FAIL")); } { uint16_t whole = 2; float sum = 0.0f; float r1 = ALGO_GetRms(3, 1, sum, whole); sum += 3 * 3; float r2 = ALGO_GetRms(4, 2, sum, whole); int okr = __aty_close_d(r2, 3.5355, 1e-3); if(okr) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" RMS r1 = %f, r2 = %f, %s\r\n", r1, r2, (okr ? "PASS" : "FAIL")); } { double arr[5] = {1.0, 2.0, 3.0, 5.0, 8.0}; uint16_t i1 = ALGO_BinarySearch(arr, 5, 5.0); uint16_t i2 = ALGO_BinarySearch(arr, 5, 4.0); int okb1 = __aty_equal_u((uint32_t)i1, (uint32_t)3); int okb2 = __aty_equal_u((uint32_t)i2, (uint32_t)3); if(okb1) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; if(okb2) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" BinSearch i1 = %d, i2 = %d, %s\r\n", i1, i2, ((okb1 && okb2) ? "PASS" : "FAIL")); } { uint8_t g8 = 0; uint8_t s8 = 0xF0; ALGO_InvertUint8_Group(&g8, &s8); uint16_t g16 = 0; uint16_t s16 = 0x1234; ALGO_InvertUint16_Group(&g16, &s16); uint32_t g32 = 0; uint32_t s32 = 0x12345678; ALGO_InvertUint32_Group(&g32, &s32); int oki = __aty_equal_u((uint32_t)g8, (uint32_t)0x0Fu) && __aty_equal_u((uint32_t)g16, (uint32_t)0x2C48u) && __aty_equal_u((uint32_t)g32, (uint32_t)0x1E6A2C48u); if(oki) ALGO_AlgorithmBase_ATY_Test_Pass++; else ALGO_AlgorithmBase_ATY_Test_Fail++; printf_ATY_D(" Invert g8 = 0x%x, g16 = 0x%x, g32 = 0x%x, %s\r\n", g8, g16, g32, (oki ? "PASS" : "FAIL")); } printf_ATY_D("%sEND: Pass = %d, Fail = %d\r\n", ALGO_AlgorithmBase_ATY_TAG, ALGO_AlgorithmBase_ATY_Test_Pass, ALGO_AlgorithmBase_ATY_Test_Fail); return ALGO_AlgorithmBase_ATY_Test_Fail; } #endif /* ALGO_AlgorithmBase_ATY_Test_ATY */ #endif /* __ALGO_AlgorithmBase_ATY_C */ /******************************** End Of File *********************************/