Где я могу найти самую быструю atof реализацию в мире?

19
задан Mysticial 15 December 2014 в 07:37
поделиться

4 ответа

Каково Ваше требование точности? Если Вам действительно нужен он "корректный" (всегда получает ближайшее значение с плавающей точкой к указанному десятичному числу), вероятно, будет трудно разбить стандартные версии библиотеки (кроме удаления поддержки локали, которую Вы уже сделали), так как это требует выполнения арифметики произвольной точности. Если Вы готовы терпеть ulp или две из ошибки (и больше, чем это для поднормали), вид подхода, предложенного cruzer's, может работать и может быть быстрее, но это определенно не произведет < 0.5ulp вывод. Вы добьетесь большего успеха мудрые точностью, чтобы вычислить целые и дробные части отдельно и вычислить часть в конце (например, для 12 345,6789, для вычислений его как 12 345 + 6789 / 10000.0, а не 6*.1 + 7*.01 + 8*.001 + 9*0.0001), так как 0.1 иррациональная двоичная дробь, и ошибка накопится быстро, поскольку Вы вычисляете 0.1^n. Это также позволяет Вам сделать большую часть математики с целыми числами вместо плаваний.

инструкции BCD не были реализованы в аппаратных средствах начиная с (IIRC) эти 286 и просто микрокодируются в наше время. Они вряд ли будут особенно высокоэффективны.

10
ответ дан 30 November 2019 в 04:40
поделиться

Я помню, что у нас было приложение Winforms, которое работало так медленно при парсинге некоторых файлов обмена данными, и все мы думали, что это была перегрузка сервера дб, но наш умный босс на самом деле узнал, что узкое место было в вызове, который преобразовывал проанализированные строки в десятичные числа!

самое простое должно циклично выполниться для каждой цифры (символ) в строке, сохранить рабочее общее количество, умножиться, общее количество 10 затем добавляют значение следующей цифры. Продолжите делать это, пока Вы не достигаете конца строки, или Вы встречаетесь с точкой. Если Вы встречаетесь с точкой, разделяете часть целого числа от дробной части, то имеете множитель, который делит себя на 10 для каждой цифры. Продолжите складывать их, когда Вы идете.

Пример: 123.456

рабочее общее количество = 0, добавьте 1 (теперь, это 1), рабочее общее количество = 1 * 10 = 10, добавьте 2 (теперь, это 12), рабочее общее количество = 12 * 10 = 120, добавьте 3 (теперь, это 123), встретился с точкой, подготовьтесь ко множителю дробной части = 0.1, умножьтесь на 4, доберитесь 0.4, добавьте к рабочему общему количеству, делает 123,4 множителя = 0.1 / 10 = 0.01, умножьтесь на 5, доберитесь 0.05, добавьте к рабочему общему количеству, делает 123,45 множителя = 0.01 / 10 = 0.001, умножьтесь на 6, доберитесь 0.006, добавьте к рабочему общему количеству, делает 123.456

, Конечно, тестируя на правильность числа, а также отрицательные числа сделают это более сложным. Но если можно "предположить", что вход корректен, можно сделать код намного более простым и быстрее.

1
ответ дан 30 November 2019 в 04:40
поделиться

Вы рассмотрели изучение наличия GPU, это работает? Если можно загрузить строки в память GPU и иметь ее, обрабатывают их всех, можно найти хороший алгоритм, который будет работать значительно быстрее, чем процессор.

Поочередно, сделайте это в FPGA - существуют платы PCI-E FPGA, которые можно использовать для создания произвольных сопроцессоров. Используйте DMA для указания на FPGA на часть памяти, содержащей массив строк, Вы хотите преобразовать и позволить ему свист через них оставляющий преобразованные значения.

Вы посмотрели на четырехъядерный процессор? Реальное узкое место в большинстве этих случаев является доступом к памяти так или иначе...

-Adam

0
ответ дан 30 November 2019 в 04:40
поделиться

Я реализовал кое-что, что может вам пригодиться. По сравнению с atof это примерно в 5 раз быстрее, а при использовании с __ forceinline примерно в 10 раз быстрее. Еще одна приятная вещь заключается в том, что она имеет точно такую ​​же арифметику, что и реализация crt. Конечно, у него есть и минусы:

  • он поддерживает только числа с плавающей запятой одинарной точности,
  • и не сканирует никаких специальных значений, таких как #INF и т. Д.
__forceinline bool float_scan(const wchar_t* wcs, float* val)
{
int hdr=0;
while (wcs[hdr]==L' ')
    hdr++;

int cur=hdr;

bool negative=false;
bool has_sign=false;

if (wcs[cur]==L'+' || wcs[cur]==L'-')
{
    if (wcs[cur]==L'-')
        negative=true;
    has_sign=true;
    cur++;
}
else
    has_sign=false;

int quot_digs=0;
int frac_digs=0;

bool full=false;

wchar_t period=0;
int binexp=0;
int decexp=0;
unsigned long value=0;

while (wcs[cur]>=L'0' && wcs[cur]<=L'9')
{
    if (!full)
    {
        if (value>=0x19999999 && wcs[cur]-L'0'>5 || value>0x19999999)
        {
            full=true;
            decexp++;
        }
        else
            value=value*10+wcs[cur]-L'0';
    }
    else
        decexp++;

    quot_digs++;
    cur++;
}

if (wcs[cur]==L'.' || wcs[cur]==L',')
{
    period=wcs[cur];
    cur++;

    while (wcs[cur]>=L'0' && wcs[cur]<=L'9')
    {
        if (!full)
        {
            if (value>=0x19999999 && wcs[cur]-L'0'>5 || value>0x19999999)
                full=true;
            else
            {
                decexp--;
                value=value*10+wcs[cur]-L'0';
            }
        }

        frac_digs++;
        cur++;
    }
}

if (!quot_digs && !frac_digs)
    return false;

wchar_t exp_char=0;

int decexp2=0; // explicit exponent
bool exp_negative=false;
bool has_expsign=false;
int exp_digs=0;

// even if value is 0, we still need to eat exponent chars
if (wcs[cur]==L'e' || wcs[cur]==L'E')
{
    exp_char=wcs[cur];
    cur++;

    if (wcs[cur]==L'+' || wcs[cur]==L'-')
    {
        has_expsign=true;
        if (wcs[cur]=='-')
            exp_negative=true;
        cur++;
    }

    while (wcs[cur]>=L'0' && wcs[cur]<=L'9')
    {
        if (decexp2>=0x19999999)
            return false;
        decexp2=10*decexp2+wcs[cur]-L'0';
        exp_digs++;
        cur++;
    }

    if (exp_negative)
        decexp-=decexp2;
    else
        decexp+=decexp2;
}

// end of wcs scan, cur contains value's tail

if (value)
{
    while (value<=0x19999999)
    {
        decexp--;
        value=value*10;
    }

    if (decexp)
    {
        // ensure 1bit space for mul by something lower than 2.0
        if (value&0x80000000)
        {
            value>>=1;
            binexp++;
        }

        if (decexp>308 || decexp<-307)
            return false;

        // convert exp from 10 to 2 (using FPU)
        int E;
        double v=pow(10.0,decexp);
        double m=frexp(v,&E);
        m=2.0*m;
        E--;
        value=(unsigned long)floor(value*m);

        binexp+=E;
    }

    binexp+=23; // rebase exponent to 23bits of mantisa


    // so the value is: +/- VALUE * pow(2,BINEXP);
    // (normalize manthisa to 24bits, update exponent)
    while (value&0xFE000000)
    {
        value>>=1;
        binexp++;
    }
    if (value&0x01000000)
    {
        if (value&1)
            value++;
        value>>=1;
        binexp++;
        if (value&0x01000000)
        {
            value>>=1;
            binexp++;
        }
    }

    while (!(value&0x00800000))
    {
        value<<=1;
        binexp--;
    }

    if (binexp<-127)
    {
        // underflow
        value=0;
        binexp=-127;
    }
    else
    if (binexp>128)
        return false;

    //exclude "implicit 1"
    value&=0x007FFFFF;

    // encode exponent
    unsigned long exponent=(binexp+127)<<23;
    value |= exponent;
}

// encode sign
unsigned long sign=negative<<31;
value |= sign;

if (val)
{
    *(unsigned long*)val=value;
}

return true;
}
3
ответ дан 30 November 2019 в 04:40
поделиться