Автор Тема: Увеличение быстродействия программы при работе на "С" с типом float  (Прочитано 4083 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Провел ряд испытаний на своем stm32f429 по производительности с типом float32_t и получил очень необычный результат  123123.
По порядку:
(чем больше попугаев - тем быстрее работает функция. Используется математический сопроцессор для float )

Циклы FOR или WHILE 
for =6726 попугаев
while =6726 попугаев
Вывод: пофиг на сегодня что использовать. Лидера нет.

Логарифмы FAST_LOG2() & LOG2F()

fast_log2  программа с пред подсчетом таблицы
//fast-log2 d 3 раза быстрее log2f()
#define  LogPrecisionLevel  5
#define  LogTableSize  (1<<(LogPrecisionLevel+1))
float32_t log_table[LogTableSize];
uint32_t q, qm1;

//fast log2 ----------------------------------
 float fastLog2(float x) {
     uint32_t bits= *(uint32_t *) &x;
    // int bits = Float.floatToRawIntBits(x);
     uint32_t e = (bits >> 23) & 0xff;
     uint32_t m = (bits & 0x7fffff);
    return (e == 0 ? log_table[m >> qm1] : e + log_table[((m | 0x00800000) >> q)]);
}

/**
 * Compute lookup table for a given base table size.
 *
 * @param n The number of bits to keep from the mantissa. Table storage =
 *          2^(n+1) * 4 bytes, e.g. 64Kb for n=13. Must be in the range
 *          0<=n<=23
 */
 void populateLUT(void) {

     int size = 1 << (LogPrecisionLevel + 1);

    q = 23 - LogPrecisionLevel;
    qm1 = q - 1;

    for (int i = 0; i < size; i++) {
        log_table[i] = (float) (log(i << q) / log(2)) - 150;
    }
}

//fast log2 ----------------------------------


Результат теста (сравниваем со стандартным, включенным в компилятор log2f(), и у fast_log2() точность 5 знаков )
fast_log2() =3445
log2f() =1388
Вывод: редкий случай когда сторонняя программа работает лучше чем встроенная.

SINF() & ARM_SIN_F32() от DSPLIB
sinf() =560.....2453 зависит от входных значений.
arm_sin_f32() =2551
Вывод: arm_sin_f32() от DSPLIB считает быстрее. Однако подправили что-то. sinf() ведет себя непредсказуемо по скорости. Лучше его не использовать.

Корень квадратный из float : fast_sqrt() & sqrtf() & arm_sqrt_f32()

fast_sqrt()
loat fast_sqrt(float a) {

    float b = a;
    int *x = (int*) (&b); // here I get integer pointer to float b which allows me to directly change bits from float reperesentation
    int c = ((*x >> 23) & 255) - 127; // here I get mantisa, that is exponent of 2 (floats are like scientific notation 1.111010101... * 2^n)
    if(c < 0) c = -((-c) >> 1); // ---
        //   |--> This is for halfing the mantisa
    else c >>= 1;               // ---
    *x &= ~(255 << 23); // here space reserved for mantisa is filled with 0s
    *x |= (c + 127) << 23; // here new mantisa is put in place
    for(int i = 0; i < 5; i++) b = (b + a / b) / 2; // here normal square root approximation runs 5 times (I assume even 2 or 3 would be enough)
    return b;
}

Результат теста:

fast_sqrt() =1030
sqrtf() =4393
arm_sqrt_f32()=3187

Вывод: не порадовала работа DSPLIB , ну fast_sqrt возможно неудачную нашел. Пока лидер опять стандартная функция sqrtf().

Дополнительный тест по sqrt(x*x+y*y) нужная тема для прорисовки спектра. Вычисление амплитуды.
Результат:
sqrtf(x*x+y*y) =3354
arm_sqrt_f32(x*x+y*y)=3035
Результат:
sqrtf() лучше, но отрыв сократился.  Но там немного отличается процедура запуска функций arm_sqrt_f32(in, *out).


Абсолютное значение fabsf(x) & структура типа: (x?x:-x)
Сравнение с популярным строковым выбором по условию типа: x<0?-x:x
fabsf(x)=9757
(x?x:-x) = 7059
Результат: не выеживаемся и пишем fabsf(x).




« Последнее редактирование: Декабрь 17, 2020, 08:50:41 pm от Сергей »
Да да, я знаю, у меня ничего не получится )))

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Компилятор GCC 2017 года с опцией -Ofast
Да да, я знаю, у меня ничего не получится )))

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
О попугаях...
1 попугай - это 10240 вычислений типа arr[ii]*= sqrtf(arr[ii]); где   arr[ii] float32_t со значениям внутри 111.00003124

       for (int f = 0; f < 10; f++) {
            for (int ii = 0; ii < 1024; ii++) {
                arr[ii] *= fabsf(arr[ii]);
                arr[ii]*=-1;
            }
        }

Да да, я знаю, у меня ничего не получится )))

Оффлайн GenaSPB

  • Jr. Member
  • **
  • Сообщений: 74
-fno-math-errno -funroll-loops -fgraphite-identity -ffunction-sections -fdata-sections -ffat-lto-objects -ftree-vectorizeДобавить попробуйте

Да и -flto

Опции должны и компидятору и линкеру идти

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Да с этими ключами производительность увеличилась на 15% !!!!!
-fno-math-errno -funroll-loops  -ffunction-sections -fdata-sections -ffat-lto-objects -ftree-vectorize
Да да, я знаю, у меня ничего не получится )))

Оффлайн Relayer

  • Hero Member
  • *****
  • Сообщений: 1006
  • UR5FFR
Аккуратнее с плавающими константами иначе можете получить тормоза на ровном месте
https://mcuoneclipse.com/2019/03/29/be-aware-floating-point-operations-on-arm-cortex-m4f/
В любой схеме есть как минимум одна ненужная деталь :)

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Да, спасибо, это старая болячка с float  и double.

Давно перешел на запись констант 1.0f   
Да да, я знаю, у меня ничего не получится )))