Piszę bibliotekę która m.in. pobiera liczby z tekstu i konwertuje je do postaci double. Po kilku benchmarkach doszedłem do takiej, jak na razie najszybszej wersji (funkcja parseinteger):
double __forceinline parsehex(TCHAR *&text)
{
unsigned int hexval = 0;
int pos = 0;
// pobierz maksymalnie osiem znaków, ale przerwij na pierwszym nieszesnastkowym znaku
while (ISTYPE(*text, ISTYPE_HEX) && (pos < 8)) // 1234567890ABCDEFabcdef
{
hexval = hexval<<4 | hexlookuptable[*text];
text++;
pos++;
}
return (double)hexval;
}
// oblicza wartość ułamka. Zmienna text powinna wskazywać pierwszą cyfrę po przecinku
double __forceinline parseulamek(TCHAR *&text)
{
unsigned int ulamek = 0;
int pos = 0;
while (ISTYPE(*text, ISTYPE_NUM) && (pos < 9))
{
ulamek = ulamek * 10 + hexlookuptable[*text];
text++;
pos++;
}
// a resztę cyfr ułamka zignoruj
while (ISTYPE(*text, ISTYPE_NUM))
{
text++;
}
return (double)ulamek / exponentmap[pos];
}
double __forceinline parseinteger(TCHAR *&text)
{
double result;
int pos = 0;
// to jest liczba - jeżeli zaczyna się od 0x to skonwertuj do postaci dziesiętnej
#ifdef UNICODE
if ((*(int*)text == ('x'<<16 | '0')) && ISTYPE(*(text+2), ISTYPE_HEX)) // 1234567890ABCDEFabcdef
#else
if ((*(short*)text == 'x0') && ISTYPE(*(text+2), ISTYPE_HEX)) // 1234567890ABCDEFabcdef
#endif
{
text+=2;
result = parsehex(text);
}
else
{
// to jest liczba dziesiętna - pobierz maksymalnie 9 znaków by nie przepelnic int'a.
// Jeżeli liczba będzie miała więcej cyft, to zaczniemy używać double do skompletowania jej.
// TODO: dodaj obsługę exponentu
unsigned int calkowita = 0;
while (ISTYPE(*text, ISTYPE_NUM) && (pos < 9))
{
calkowita = calkowita * 10 + hexlookuptable[*text];
text++;
pos++;
}
if (*text == '.') // liczba z przecinkiem
{
// pomiń przecinek i tym samym sposobem wczytaj część ułamkową
text++;
result = (double)calkowita + parseulamek(text);
}
else if (ISTYPE(*text, ISTYPE_NUM))
{
// liczba jest dluzsza niz 9 znakow, przskocz z int na double
result = (double)calkowita;
while (ISTYPE(*text, ISTYPE_NUM))
{
result = result * 10 + hexlookuptable[*text];
text++;
pos++;
}
if (*text == '.') // liczba z przecinkiem
{
// pomiń przecinek i tym samym sposobem wczytaj część ułamkową
text++;
result += parseulamek(text);
}
}
else // koniec liczby całkowitej
{
result = (double)calkowita;
}
}
return result;
}
Tablice użyte tutaj mają za zadanie przyspieszenie obliczania, np.
- hexlookuptable[] na pozycji cyfry '0' ma (int)0, na pozycji 'A' oraz 'a' jest (int)10;
- ISTYPE to makro używjące tablicy typemap, która przypisuje kolejne znaki ascii do grupy {cyfra, liczba, hex, ...} - coś w rodzaju isdigit, isascii...
Wszystkie tabele umieściłem tu http://sapero.pastebin.com/f40cb6e81
Macie lepszy pomysł by to zoptymalizować? Uprzedzam, że gotowe funkcje typu atof, sscanf są o wiele wolniejsze. Sprawdziłem chyba wszystkie z crt.</cpp>