c-funktion laufzeit bzw. geschwindigkeit



  • Du solltest wirklich mal die Funktion fertigmachen. Da kann sich noch hundertmal was am Laufzeitverhalten ändern. Richtig beurteilen kannst du es erst, wenn du ganz fertig bist. Leider ist halt der Borland-Compiler echt mies. Das ist so ziemlich der einzige halbwegs aktuelle Compiler, den sogar ein Assembler-Anfänger in der Ausführungsgeschwindigkeit schlägt.



  • re

    also jetz mal die gesammte funktion

    // globales array
    char array[] = {"00010203040506070809101112131415161718192021222324252627282930313233343536373839"
                        "40414243444546474849505152535455565758596061626364656667686970717273747576777879"
                        "8081828384858687888990919293949596979899"};
    
    // die funktion
    inline void TFMain::ctoi(char *t_buffer,unsigned int t_value)
    {
       char buffer[16];
       unsigned int uih;
       unsigned int uil;
       unsigned int uihh;
       unsigned int uihl;
       unsigned int uilh;
       unsigned int uill;
       unsigned int temp;
    
       uih = t_value / 10000;
       uil = t_value - (uih * 10000);
    
       uihh = uih / 100;
       uihl = uih - (uihh * 100);
       uilh = uil / 100;
       uill = uil - (uilh * 100);;
    
       short int *p = (short int*) buffer;
       short int *q = (short int*) array;
       p[0] = q[uihh];
       p[1] = q[uihl];
       p[2] = q[uilh];
       p[3] = q[uill];
       buffer[8] = '\0';
    
       char *c = buffer;
       char *tc = t_buffer;
       while(*c == '0') ++c;
       while(*c) *(tc++) = *(c++);
    }
    

    derzeit braucht die funktion fuer die ersten 10000 zahlen rund 1,92 mio. ticks.
    waere fein wenn man da noch was drann drehen koennte.
    kann man da noch was mit parallelitaet machen ?

    deshalb hatte ich zuerst auch den modulo dabei ,weil ich dachte, das er die division und modulo parallel ausfuehren kann. so geht das ja schwerlich, weil er auch das ergebnis der division warten muss.

    Meep Meep


  • Mod

    versuch mal das zu messen:

    inline void TFMain::ctoi(char* t_buffer, unsigned t_value)
    {
        t_buffer += t_value >= 100
            ? t_value >= 10000
                ? 6
                : t_value >= 1000
                    ? 5
                    : 4
            : t_value >= 10
                ? 3
                : 2;
        *--t_buffer = '\0';
        do
        {
            *--t_buffer = '0' + t_value % 10;
        }
        while( t_value /= 10 );
    }
    

    wenn er / und % nicht zusammenfassen kann, gibt es leider kaum etwas, um den compiler zu heilen.



  • hallo camper

    also mit dem bcb compiliert, ist deine funktion nur minimal schneller als atoi vom bcb selbst.

    messung fuer die ersten 1 millionen zahlen:

    atoi : 556 mio. ticks
    deine : 551 mio. ticks

    meine alte vresion hab ich nun etwas umgeschrieben und komme jetz
    auf 172 mio. ticks. also ungefaehr 3 mal so schnell.
    leider hab ich keinen anderen compiler da, damit ich das mal wo anders testen kann. vielleicht waere deine version schneller als meine und der borland macht nur mistcode drauss.

    koennte mal jemand vielleicht atoi mit 1 bis 1000000 durchlaufen lassen, mit nem guten compiler, und das mit rdtsc messen ?
    damit ich mal nen anhaltspunkt habe ?
    sollte man auch dazu schreiben, auf welchem prozi das getestet wurde.
    ich test grad auf nem AMD64 schleppi

    cermy

    Meep Meep


  • Mod

    #include <memory>
    
    char smallNums[10000][6] = { 0 };
    char NullNums[10000][5] = { 0 };
    
    char const* const init_smallNums()
    {
        for( int i = 0; i < 10000; ++i )
        {
            int v = i;
            char* buf = &smallNums[i][0];
            char x = v >= 100
            ? v >= 1000
                ? 4
                : 3
            : v >= 10
                ? 2
                : 1;
            buf[ 5 ] = x;
            buf += x;
            do
            {
                *--buf = '0' + v % 10;
            }
            while( v /= 10 );
        }
        for( int i = 0; i < 10000; ++i )
        {
            int v = i;
            char* buf = &NullNums[i][0];
            for( int j = 3; j >= 0; --j )
            {
                buf[j] = '0' + v % 10;
                v /= 10;
            }
        }
        return smallNums[0];
    }
    
    char const* const init_smallNums_v = init_smallNums();
    
    inline void ctoi(char* t_buffer, unsigned t_value)
    {
        static char const n10000[] = "10000";
        static char const n100000000[] = "100000000";
        if( t_value < 100000000 )
        {
            if( t_value <= 10000 )
            {
                if( t_value < 10000 )
                {
                    memcpy( t_buffer, smallNums[ t_value ], smallNums[ t_value ][ 5 ] + 1 );
                }
                else
                {
                    memcpy( t_buffer, n10000, sizeof( n10000 ) );
                }
            }
            else
            {
                unsigned v = t_value / 10000;
                t_value %= 10000;
                memcpy( t_buffer, smallNums[ v ], smallNums[ v ][ 5 ] );
                memcpy( t_buffer + smallNums[ v ][ 5 ], NullNums[ t_value ], 5 );
            }
        }
        else
        {
            if( t_value != 100000000 )
            {
                unsigned v = t_value / 100000000;
                t_value %= 100000000;
                char x;
                memcpy( t_buffer, smallNums[ v ], x = smallNums[ v ][ 5 ] );
                v = t_value / 10000;
                t_value %= 10000;
                memcpy( t_buffer += x, NullNums[ v ], 4 );
                memcpy( t_buffer + 4, NullNums[ t_value ], 5 );
            }
            else
            {
                memcpy( t_buffer, n100000000, sizeof( n100000000 ) );
            }
        }
    }
    #include <iostream>
    typedef unsigned long long u64;
    inline u64 rdtsc()
    {
        __asm rdtsc;
    }
    int main()
    {
        u64 gtime;
        char xyz[10] = "";
        gtime = rdtsc();
        for( unsigned i = 0; i < 10000000; ++i )
        {
            ctoi(xyz,i);
        }
        gtime = rdtsc() - gtime;
        std::cout << gtime << '\t' << double(gtime)/10000000.0 << std::endl;
        char y;
        std::cin >> y;
        return 0;
    }
    

    mal zum spass mit p4 und vc++ ergibt ungefähr 150 ticks pro zahl. allerdings benutzt vc auch rep mosb (ugh!) - dabei hab ich die anzahl der zeichen extra als konstante angegeben um aggresivere optimierung zu erlauben. man könnte versucht sein, das ganze irgendwie mit FBSTP zu machen... allerdings ist dessen performance grauenvoll ( 172 takte bei amd )



  • Was magst du jetzt? Zahl zu String oder String zu Zahl? Du redest ständig von atoi (also String zu Zahl), deine Funktion macht aber das Umgekehrte.



  • re

    meinte natuerlich itoa. bin scho etwas durcheinander heute.

    @camper:
    du baust da ja ne ganz schoen grosse table auf. so grosse tables wollte ich jedoch vermeiden. is zwar im gesammten gesehen nicht viel speicher, aber fuer meinen geschmack etwas zu gross. vorallem wenn der code durch nicht wirklich viel schneller ist.

    inzwischen bin ich auch schon auf 167 ticks pro zahl runter gekommen.

    gibts dafuer eigendlich nicht vielleicht schon ne asm optimierte version ?
    koennte man ja fast meinen, da sowas doch recht haeufig gebraucht wird.
    denk ich mal so.

    Meep Meep


  • Mod

    ich teste auf p4, du auf amd64... rechne besser mal damit, dass es bei dir nur ungefähr 2/3 soviele takte braucht 😉



  • Ich wundere mich gerade, warum in der GNU libc-Doku nirgends itoa erwähnt wird...



  • Also die Methode von camper braucht auf einem 2GHz Athlon XP mit gcc-3.4.3 unter Linux 55 Zyklen, auf einem Xeon 2.8GHz 155.

    Der Unterschied dürfte aber auch daran liegen, dass ersterer eine bessere memcpy-Implementierung hat. Der Athlon XP läuft mit Debian, der Xeon mit RedHat 9.



  • re

    messt doch mal einer von euch meinen zusammen geschusterten code aus, fallse wer lust hat.

    static inline __fastcall void TFMain::func(char *t_buffer, unsigned int t_value)
    {
       char buffer[15];
    
       unsigned int v[5]={0,0,0,0,0};
    
       if(t_value >= 100000000)
       {
          v[0] = t_value / 100000000;
          t_value -= v[0] * 100000000;
       }
       if(t_value >= 1000000)
       {
          v[1] = t_value / 1000000;
          t_value -= v[1] * 1000000;
       }
       if(t_value >= 10000)
       {
          v[2] = t_value / 10000;
          t_value -= v[2] * 10000;
       }
       if(t_value >= 100)
       {
          v[3] = t_value / 100;
          t_value -= v[3] * 100;
       }
       v[4] = t_value;
    
       short int *p = (short int*) buffer;
       //unsigned int *p = (unsigned int*) buffer;
       short int *si1 = (short int*) array;
       short int *si2 = (short int*) array;
    
       short int *q = (short int*) t_buffer;
       p[0] = si1[v[0]];
       p[1] = si1[v[1]];
       p[2] = si1[v[2]];
       p[3] = si1[v[3]];
       p[4] = si1[v[4]];
       buffer[10] = '\0';
    
       char *c = buffer;
       char *d = t_buffer;
       while(*c == '0') ++c;
       while(*c) *(d++) = *(c++);
       *d = '\0';
    }
    

    @Ringding:

    55 ticks is aber ein sehr guter wert. wird wahrscheinlich am xeon liegen schaetz ich mal.
    koenntest mal dein teil disassemblieren und nachgucken oder posten was der da macht ? vielleicht kann man das ja irgendiwe gebrauchen. hab leider keinen xeon bei der hand. ausser bei meiner freundin im auto die xeonlampen. aber das duerfte doch was anderes sein ;o)

    Meep Meep


  • Mod

    aus

    while(*c) *(d++) = *(c++);
       *d = '\0';
    

    machst du besser

    while(*d++=*c++);
    

    oder

    strcpy(d,c);
    

    was besser ist, hängt hier wirklich vom compiler ab, i.allg. ist letzteres zu empfehlen.
    ich habs mal ein mit inline assembler probiert, es ist nicht gänzlich optimal aber gut genug (selbes framework wie zuvor, nur die funktion hat sich geändert)

    inline void ctoi(char* t_buffer, unsigned t_value)
    {
        unsigned static const n10000 = 10000;
        unsigned static const n100000000 = 100000000;
        __asm
        {
            mov     eax, t_value
            mov     ecx, t_buffer
            xor     edx, edx
            cmp     eax, 100000000
            jae     ae100000000
            cmp     eax, 10000
            jae     ae10000
            mov     edx, smallNums[ eax + eax * 4 ]
            mov     [ ecx ], edx
            mov     byte ptr [ ecx + 4 ], 0
            jmp     getout
    ae10000:div     n10000
            mov     ebx, smallNums[ eax + eax * 4 ]
            movzx   eax, smallNums[ eax + eax * 4 + 4 ]
            mov     edx, NullNums[ edx * 4 ]
            mov     [ ecx ], ebx
            mov     [ ecx + eax ], edx
            mov     byte ptr [ ecx + eax + 4 ], 0
            jmp     getout
    ae100000000:
            div     n100000000
            mov     ebx, smallNums[ eax + eax * 4 ]
            movzx   eax, smallNums[ eax + eax * 4 + 4 ]
            mov     [ ecx ], ebx
            add     ecx, eax
            mov     eax, edx
            xor     edx, edx
            div     n10000
            mov     eax, NullNums[ eax * 4 ]
            mov     edx, NullNums[ edx * 4 ]
            mov     [ ecx ], eax
            mov     [ ecx + 4 ], edx
            mov     byte ptr [ ecx + 8 ], 0
    getout:
        }
    }
    

    ist ungefähr doppelt so schnell wie zuvor. allerdings sind das ja auch keine realistischen messungen. im grunde ist es sowieso nur spielerei.

    bei borland musst du die speicherzugriffe evtl so schreiben:

    movzx   eax, smallNums[ eax + eax * 4 + 4 ]
            mov     byte ptr [ ecx + 8 ], 0
    

    wird zu

    movzx   eax, [ smallNums + eax + eax * 4 + 4 ]
            mov     [ byte ptr ecx + 8 ], 0
    

    oder so.



  • Der Xeon hat 155 gebraucht, nicht 55. Der schnelle war der Athlon XP. Jo, ich werd morgen mal den Code posten.



  • @Ringding
    jo waere fein, wenn du das machen wuerdest.

    ich werd es morgen dann nochmal mit dem Metrowerks probieren. is der gut ? oder auch der selbe fall wie der borland ?
    den borland hab ich eigendlich immer gerne verwendet, wegen der RAD. das ging recht schnell und unproblematisch. gui mit reiner api ist mir irgendwie zu anstrengend.

    inwieweit kann man eigendlich asm routinen mit C(++) einbauen ? ich glaub mich zu erinnern das die compiler da auch unterschiedlichen syntax verwenden. naja dazu wird wahrscheinlich hier schon oft genug diekutiert worden sein. das such ich mir mal raus.

    n8

    Meep Meep



  • 113 braucht der Athlon XP für deinen letzten Code.

    Also, der erzeugte Code für campers Funktion in Verbindung mit dieser schaut so aus:

    static char digits[10];
    
    void doit()
    {
        int i;
    
        for (i=0; i<1000000; i++)
        {
            ctoi(digits, i);
        }
    }
    

    Das ist der mit den 55 Cycles.

    00000000  55                push ebp
    00000001  89E5              mov ebp,esp
    00000003  57                push edi
    00000004  31FF              xor edi,edi
    00000006  56                push esi
    00000007  53                push ebx
    00000008  83EC1C            sub esp,byte +0x1c
    0000000B  C745F000000000    mov dword [ebp-0x10],0x0
    00000012  EB43              jmp short 0x57
    00000014  81FF10270000      cmp edi,0x2710
    0000001A  0F8710010000      ja near 0x130
    00000020  81FF0F270000      cmp edi,0x270f
    00000026  0F8667010000      jna near 0x193
    0000002C  0FB70D04000000    movzx ecx,word [0x4]
    00000033  8B1D00000000      mov ebx,[0x0]
    00000039  891DC4AD0100      mov [0x1adc4],ebx
    0000003F  66890DC8AD0100    mov [0x1adc8],cx
    00000046  47                inc edi
    00000047  8345F006          add dword [ebp-0x10],byte +0x6
    0000004B  81FF3F420F00      cmp edi,0xf423f
    00000051  0F8F9C000000      jg near 0xf3
    00000057  81FFFFE0F505      cmp edi,0x5f5e0ff
    0000005D  76B5              jna 0x14
    0000005F  81FF00E1F505      cmp edi,0x5f5e100
    00000065  0F8495000000      jz near 0x100
    0000006B  89F8              mov eax,edi
    0000006D  BB893BE655        mov ebx,0x55e63b89
    00000072  C70424C4AD0100    mov dword [esp],0x1adc4
    00000079  F7E3              mul ebx
    0000007B  89FB              mov ebx,edi
    0000007D  47                inc edi
    0000007E  C1EA19            shr edx,0x19
    00000081  69F200E1F505      imul esi,edx,dword 0x5f5e100
    00000087  8D1452            lea edx,[edx+edx*2]
    0000008A  01D2              add edx,edx
    0000008C  29F3              sub ebx,esi
    0000008E  0FBEB205000000    movsx esi,byte [edx+0x5]
    00000095  81C200000000      add edx,0x0
    0000009B  89542404          mov [esp+0x4],edx
    0000009F  89742408          mov [esp+0x8],esi
    000000A3  E8FCFFFFFF        call 0xa4
    000000A8  B85917B7D1        mov eax,0xd1b71759
    000000AD  F7E3              mul ebx
    000000AF  C1EA0D            shr edx,0xd
    000000B2  69CA10270000      imul ecx,edx,dword 0x2710
    000000B8  8B849200000000    mov eax,[edx+edx*4+0x0]
    000000BF  8986C4AD0100      mov [esi+0x1adc4],eax
    000000C5  29CB              sub ebx,ecx
    000000C7  8D8EC4AD0100      lea ecx,[esi+0x1adc4]
    000000CD  8D1C9B            lea ebx,[ebx+ebx*4]
    000000D0  8BB300000000      mov esi,[ebx+0x0]
    000000D6  897104            mov [ecx+0x4],esi
    000000D9  0FB69304000000    movzx edx,byte [ebx+0x4]
    000000E0  885108            mov [ecx+0x8],dl
    000000E3  8345F006          add dword [ebp-0x10],byte +0x6
    000000E7  81FF3F420F00      cmp edi,0xf423f
    000000ED  0F8E64FFFFFF      jng near 0x57
    000000F3  83C41C            add esp,byte +0x1c
    000000F6  5B                pop ebx
    000000F7  5E                pop esi
    000000F8  5F                pop edi
    000000F9  C9                leave
    000000FA  C3                ret
    000000FB  90                nop
    000000FC  8D742600          lea esi,[esi+0x0]
    00000100  0FB70D08000000    movzx ecx,word [0x8]
    00000107  8B3500000000      mov esi,[0x0]
    0000010D  8B1504000000      mov edx,[0x4]
    00000113  8935C4AD0100      mov [0x1adc4],esi
    00000119  8915C8AD0100      mov [0x1adc8],edx
    0000011F  66890DCCAD0100    mov [0x1adcc],cx
    00000126  E91BFFFFFF        jmp 0x46
    0000012B  90                nop
    0000012C  8D742600          lea esi,[esi+0x0]
    00000130  B85917B7D1        mov eax,0xd1b71759
    00000135  89FB              mov ebx,edi
    00000137  C70424C4AD0100    mov dword [esp],0x1adc4
    0000013E  F7E7              mul edi
    00000140  C1EA0D            shr edx,0xd
    00000143  69F210270000      imul esi,edx,dword 0x2710
    00000149  8D0C52            lea ecx,[edx+edx*2]
    0000014C  29F3              sub ebx,esi
    0000014E  8D3409            lea esi,[ecx+ecx]
    00000151  0FBE8605000000    movsx eax,byte [esi+0x5]
    00000158  8D9600000000      lea edx,[esi+0x0]
    0000015E  89542404          mov [esp+0x4],edx
    00000162  89442408          mov [esp+0x8],eax
    00000166  E8FCFFFFFF        call 0x167
    0000016B  0FBE9605000000    movsx edx,byte [esi+0x5]
    00000172  8D349B            lea esi,[ebx+ebx*4]
    00000175  0FB68604000000    movzx eax,byte [esi+0x4]
    0000017C  8B8E00000000      mov ecx,[esi+0x0]
    00000182  898AC4AD0100      mov [edx+0x1adc4],ecx
    00000188  8882C8AD0100      mov [edx+0x1adc8],al
    0000018E  E9B3FEFFFF        jmp 0x46
    00000193  8B55F0            mov edx,[ebp-0x10]
    00000196  C70424C4AD0100    mov dword [esp],0x1adc4
    0000019D  0FBE8205000000    movsx eax,byte [edx+0x5]
    000001A4  81C200000000      add edx,0x0
    000001AA  89542404          mov [esp+0x4],edx
    000001AE  40                inc eax
    000001AF  89442408          mov [esp+0x8],eax
    000001B3  E8FCFFFFFF        call 0x1b4
    000001B8  E989FEFFFF        jmp 0x46
    

    Die calls sind memcpy.



  • Mein eigener Versuch, ohne Tabelle:

    inline void ctoi(char* b, unsigned v)
    {
        static int pow10[6] = {1, 10, 100, 1000, 10000, 100000};
        int m, pi, p;
    
        if (v >= 100000) {
            m = 100000; pi = 5;
        } else if (v >= 10000) {
            m = 10000; pi = 4;
        } else if (v >= 1000) {
            m = 1000; pi = 3;
        } else if (v >= 100) {
            m = 100; pi = 2;
        } else if (v >= 10) {
            m = 10; pi = 1;
        } else {
            m = 1; pi = 0;
        }
    
        for (p=0; ; pi--)
        {
            int d;
            if (v >= 5*m)
                if (v < 8*m)
                    if (v < 7*m)
                        if (v >= 6*m)
                            { b[p++] = '6'; d = 6*m; }
                        else
                            { b[p++] = '5'; d = 5*m; }
                    else
                        { b[p++] = '7'; d = 7*m; }
                else
                    if (v >= 9*m)
                        { b[p++] = '9'; d = 9*m; }
                    else
                        {b[p++] = '8'; d = 8*m; }
            else
                if (v >= 2*m)
                    if (v < 4*m)
                        if (v >= 3*m)
                            { b[p++] = '3'; d = 3*m; }
                        else
                            { b[p++] = '2'; d = 2*m; }
                    else
                        { b[p++] = '4'; d = 4*m; }
                else
                    if (v >= m)
                        { b[p++] = '1'; d = m; }
                    else
                        { b[p++] = '0'; d = 0; }
            v -= d;
            if (!pi)
                break;
            m = pow10[pi-1];
        }
        b[p] = '\0';
    }
    

    103 Cycles am Athlon / 165 am Xeon. Am Xeon schwankt es aber ziemlich stark (157 - 180)



  • morgaehn

    hab jetz mal den metrowerks installiert und hab campers version, von seite 2 - ganz oben, getestet. grad mal 65 ticks. beim borland grad mal 511 ticks. also ein klitzekleiner unterschied. das is schon ein bisschen hart, was der bcb so veranstaltet. mal gucken wie es mit den anderen versionen aussieht.

    @Ringding

    womit sisassemle ich so nen source am besten und finde dann darin auch noch die funktion ? welche optimierungen hattest du bei deinem build ?

    Meep Meep



  • -O3 -march=athlon-xp hab ich verwendet. Zum Disassemblen hab ich den ndisasm genommen, weil der IMHO den lesbarsten Code erzeugt, zum Auffinden der Funktion den Debugger.


  • Mod

    Ringding schrieb:

    -O3 -march=athlon-xp hab ich verwendet. Zum Disassemblen hab ich den ndisasm genommen, weil der IMHO den lesbarsten Code erzeugt, zum Auffinden der Funktion den Debugger.

    nimm doch -save-temps
    ich glaube der manuelle vergleich pro stelle führt hier zu keinem guten ergebnis... du brauchst im schnitt 3.5 vergleiche pro digit, damit bist du von der laufzeit schon wieder fast an eine einzelne division heran - im gegensatz dazu kann man die divisionsmethode ja problemslos, wie oben, auch für mehr als eine stelle benutzen ohne das der rechenaufwand steigt.

    hier mal der ganze spass mit 3stelligem lookup und gcc - dass braucht also nur noch knapp 4KB.

    __attribute__((used)) char const lookup[1000][4] =
    {
        {24,'0','0','0'},{24,'0','0','1'},{24,'0','0','2'},{24,'0','0','3'},{24,'0','0','4'},
        {24,'0','0','5'},{24,'0','0','6'},{24,'0','0','7'},{24,'0','0','8'},{24,'0','0','9'},
        {16,'0','1','0'},{16,'0','1','1'},{16,'0','1','2'},{16,'0','1','3'},{16,'0','1','4'},
        {16,'0','1','5'},{16,'0','1','6'},{16,'0','1','7'},{16,'0','1','8'},{16,'0','1','9'},
        {16,'0','2','0'},{16,'0','2','1'},{16,'0','2','2'},{16,'0','2','3'},{16,'0','2','4'},
        {16,'0','2','5'},{16,'0','2','6'},{16,'0','2','7'},{16,'0','2','8'},{16,'0','2','9'},
        {16,'0','3','0'},{16,'0','3','1'},{16,'0','3','2'},{16,'0','3','3'},{16,'0','3','4'},
        {16,'0','3','5'},{16,'0','3','6'},{16,'0','3','7'},{16,'0','3','8'},{16,'0','3','9'},
        {16,'0','4','0'},{16,'0','4','1'},{16,'0','4','2'},{16,'0','4','3'},{16,'0','4','4'},
        {16,'0','4','5'},{16,'0','4','6'},{16,'0','4','7'},{16,'0','4','8'},{16,'0','4','9'},
        {16,'0','5','0'},{16,'0','5','1'},{16,'0','5','2'},{16,'0','5','3'},{16,'0','5','4'},
        {16,'0','5','5'},{16,'0','5','6'},{16,'0','5','7'},{16,'0','5','8'},{16,'0','5','9'},
        {16,'0','6','0'},{16,'0','6','1'},{16,'0','6','2'},{16,'0','6','3'},{16,'0','6','4'},
        {16,'0','6','5'},{16,'0','6','6'},{16,'0','6','7'},{16,'0','6','8'},{16,'0','6','9'},
        {16,'0','7','0'},{16,'0','7','1'},{16,'0','7','2'},{16,'0','7','3'},{16,'0','7','4'},
        {16,'0','7','5'},{16,'0','7','6'},{16,'0','7','7'},{16,'0','7','8'},{16,'0','7','9'},
        {16,'0','8','0'},{16,'0','8','1'},{16,'0','8','2'},{16,'0','8','3'},{16,'0','8','4'},
        {16,'0','8','5'},{16,'0','8','6'},{16,'0','8','7'},{16,'0','8','8'},{16,'0','8','9'},
        {16,'0','9','0'},{16,'0','9','1'},{16,'0','9','2'},{16,'0','9','3'},{16,'0','9','4'},
        {16,'0','9','5'},{16,'0','9','6'},{16,'0','9','7'},{16,'0','9','8'},{16,'0','9','9'},
        {8,'1','0','0'},{8,'1','0','1'},{8,'1','0','2'},{8,'1','0','3'},{8,'1','0','4'},
        {8,'1','0','5'},{8,'1','0','6'},{8,'1','0','7'},{8,'1','0','8'},{8,'1','0','9'},
        {8,'1','1','0'},{8,'1','1','1'},{8,'1','1','2'},{8,'1','1','3'},{8,'1','1','4'},
        {8,'1','1','5'},{8,'1','1','6'},{8,'1','1','7'},{8,'1','1','8'},{8,'1','1','9'},
        {8,'1','2','0'},{8,'1','2','1'},{8,'1','2','2'},{8,'1','2','3'},{8,'1','2','4'},
        {8,'1','2','5'},{8,'1','2','6'},{8,'1','2','7'},{8,'1','2','8'},{8,'1','2','9'},
        {8,'1','3','0'},{8,'1','3','1'},{8,'1','3','2'},{8,'1','3','3'},{8,'1','3','4'},
        {8,'1','3','5'},{8,'1','3','6'},{8,'1','3','7'},{8,'1','3','8'},{8,'1','3','9'},
        {8,'1','4','0'},{8,'1','4','1'},{8,'1','4','2'},{8,'1','4','3'},{8,'1','4','4'},
        {8,'1','4','5'},{8,'1','4','6'},{8,'1','4','7'},{8,'1','4','8'},{8,'1','4','9'},
        {8,'1','5','0'},{8,'1','5','1'},{8,'1','5','2'},{8,'1','5','3'},{8,'1','5','4'},
        {8,'1','5','5'},{8,'1','5','6'},{8,'1','5','7'},{8,'1','5','8'},{8,'1','5','9'},
        {8,'1','6','0'},{8,'1','6','1'},{8,'1','6','2'},{8,'1','6','3'},{8,'1','6','4'},
        {8,'1','6','5'},{8,'1','6','6'},{8,'1','6','7'},{8,'1','6','8'},{8,'1','6','9'},
        {8,'1','7','0'},{8,'1','7','1'},{8,'1','7','2'},{8,'1','7','3'},{8,'1','7','4'},
        {8,'1','7','5'},{8,'1','7','6'},{8,'1','7','7'},{8,'1','7','8'},{8,'1','7','9'},
        {8,'1','8','0'},{8,'1','8','1'},{8,'1','8','2'},{8,'1','8','3'},{8,'1','8','4'},
        {8,'1','8','5'},{8,'1','8','6'},{8,'1','8','7'},{8,'1','8','8'},{8,'1','8','9'},
        {8,'1','9','0'},{8,'1','9','1'},{8,'1','9','2'},{8,'1','9','3'},{8,'1','9','4'},
        {8,'1','9','5'},{8,'1','9','6'},{8,'1','9','7'},{8,'1','9','8'},{8,'1','9','9'},
        {8,'2','0','0'},{8,'2','0','1'},{8,'2','0','2'},{8,'2','0','3'},{8,'2','0','4'},
        {8,'2','0','5'},{8,'2','0','6'},{8,'2','0','7'},{8,'2','0','8'},{8,'2','0','9'},
        {8,'2','1','0'},{8,'2','1','1'},{8,'2','1','2'},{8,'2','1','3'},{8,'2','1','4'},
        {8,'2','1','5'},{8,'2','1','6'},{8,'2','1','7'},{8,'2','1','8'},{8,'2','1','9'},
        {8,'2','2','0'},{8,'2','2','1'},{8,'2','2','2'},{8,'2','2','3'},{8,'2','2','4'},
        {8,'2','2','5'},{8,'2','2','6'},{8,'2','2','7'},{8,'2','2','8'},{8,'2','2','9'},
        {8,'2','3','0'},{8,'2','3','1'},{8,'2','3','2'},{8,'2','3','3'},{8,'2','3','4'},
        {8,'2','3','5'},{8,'2','3','6'},{8,'2','3','7'},{8,'2','3','8'},{8,'2','3','9'},
        {8,'2','4','0'},{8,'2','4','1'},{8,'2','4','2'},{8,'2','4','3'},{8,'2','4','4'},
        {8,'2','4','5'},{8,'2','4','6'},{8,'2','4','7'},{8,'2','4','8'},{8,'2','4','9'},
        {8,'2','5','0'},{8,'2','5','1'},{8,'2','5','2'},{8,'2','5','3'},{8,'2','5','4'},
        {8,'2','5','5'},{8,'2','5','6'},{8,'2','5','7'},{8,'2','5','8'},{8,'2','5','9'},
        {8,'2','6','0'},{8,'2','6','1'},{8,'2','6','2'},{8,'2','6','3'},{8,'2','6','4'},
        {8,'2','6','5'},{8,'2','6','6'},{8,'2','6','7'},{8,'2','6','8'},{8,'2','6','9'},
        {8,'2','7','0'},{8,'2','7','1'},{8,'2','7','2'},{8,'2','7','3'},{8,'2','7','4'},
        {8,'2','7','5'},{8,'2','7','6'},{8,'2','7','7'},{8,'2','7','8'},{8,'2','7','9'},
        {8,'2','8','0'},{8,'2','8','1'},{8,'2','8','2'},{8,'2','8','3'},{8,'2','8','4'},
        {8,'2','8','5'},{8,'2','8','6'},{8,'2','8','7'},{8,'2','8','8'},{8,'2','8','9'},
        {8,'2','9','0'},{8,'2','9','1'},{8,'2','9','2'},{8,'2','9','3'},{8,'2','9','4'},
        {8,'2','9','5'},{8,'2','9','6'},{8,'2','9','7'},{8,'2','9','8'},{8,'2','9','9'},
        {8,'3','0','0'},{8,'3','0','1'},{8,'3','0','2'},{8,'3','0','3'},{8,'3','0','4'},
        {8,'3','0','5'},{8,'3','0','6'},{8,'3','0','7'},{8,'3','0','8'},{8,'3','0','9'},
        {8,'3','1','0'},{8,'3','1','1'},{8,'3','1','2'},{8,'3','1','3'},{8,'3','1','4'},
        {8,'3','1','5'},{8,'3','1','6'},{8,'3','1','7'},{8,'3','1','8'},{8,'3','1','9'},
        {8,'3','2','0'},{8,'3','2','1'},{8,'3','2','2'},{8,'3','2','3'},{8,'3','2','4'},
        {8,'3','2','5'},{8,'3','2','6'},{8,'3','2','7'},{8,'3','2','8'},{8,'3','2','9'},
        {8,'3','3','0'},{8,'3','3','1'},{8,'3','3','2'},{8,'3','3','3'},{8,'3','3','4'},
        {8,'3','3','5'},{8,'3','3','6'},{8,'3','3','7'},{8,'3','3','8'},{8,'3','3','9'},
        {8,'3','4','0'},{8,'3','4','1'},{8,'3','4','2'},{8,'3','4','3'},{8,'3','4','4'},
        {8,'3','4','5'},{8,'3','4','6'},{8,'3','4','7'},{8,'3','4','8'},{8,'3','4','9'},
        {8,'3','5','0'},{8,'3','5','1'},{8,'3','5','2'},{8,'3','5','3'},{8,'3','5','4'},
        {8,'3','5','5'},{8,'3','5','6'},{8,'3','5','7'},{8,'3','5','8'},{8,'3','5','9'},
        {8,'3','6','0'},{8,'3','6','1'},{8,'3','6','2'},{8,'3','6','3'},{8,'3','6','4'},
        {8,'3','6','5'},{8,'3','6','6'},{8,'3','6','7'},{8,'3','6','8'},{8,'3','6','9'},
        {8,'3','7','0'},{8,'3','7','1'},{8,'3','7','2'},{8,'3','7','3'},{8,'3','7','4'},
        {8,'3','7','5'},{8,'3','7','6'},{8,'3','7','7'},{8,'3','7','8'},{8,'3','7','9'},
        {8,'3','8','0'},{8,'3','8','1'},{8,'3','8','2'},{8,'3','8','3'},{8,'3','8','4'},
        {8,'3','8','5'},{8,'3','8','6'},{8,'3','8','7'},{8,'3','8','8'},{8,'3','8','9'},
        {8,'3','9','0'},{8,'3','9','1'},{8,'3','9','2'},{8,'3','9','3'},{8,'3','9','4'},
        {8,'3','9','5'},{8,'3','9','6'},{8,'3','9','7'},{8,'3','9','8'},{8,'3','9','9'},
        {8,'4','0','0'},{8,'4','0','1'},{8,'4','0','2'},{8,'4','0','3'},{8,'4','0','4'},
        {8,'4','0','5'},{8,'4','0','6'},{8,'4','0','7'},{8,'4','0','8'},{8,'4','0','9'},
        {8,'4','1','0'},{8,'4','1','1'},{8,'4','1','2'},{8,'4','1','3'},{8,'4','1','4'},
        {8,'4','1','5'},{8,'4','1','6'},{8,'4','1','7'},{8,'4','1','8'},{8,'4','1','9'},
        {8,'4','2','0'},{8,'4','2','1'},{8,'4','2','2'},{8,'4','2','3'},{8,'4','2','4'},
        {8,'4','2','5'},{8,'4','2','6'},{8,'4','2','7'},{8,'4','2','8'},{8,'4','2','9'},
        {8,'4','3','0'},{8,'4','3','1'},{8,'4','3','2'},{8,'4','3','3'},{8,'4','3','4'},
        {8,'4','3','5'},{8,'4','3','6'},{8,'4','3','7'},{8,'4','3','8'},{8,'4','3','9'},
        {8,'4','4','0'},{8,'4','4','1'},{8,'4','4','2'},{8,'4','4','3'},{8,'4','4','4'},
        {8,'4','4','5'},{8,'4','4','6'},{8,'4','4','7'},{8,'4','4','8'},{8,'4','4','9'},
        {8,'4','5','0'},{8,'4','5','1'},{8,'4','5','2'},{8,'4','5','3'},{8,'4','5','4'},
        {8,'4','5','5'},{8,'4','5','6'},{8,'4','5','7'},{8,'4','5','8'},{8,'4','5','9'},
        {8,'4','6','0'},{8,'4','6','1'},{8,'4','6','2'},{8,'4','6','3'},{8,'4','6','4'},
        {8,'4','6','5'},{8,'4','6','6'},{8,'4','6','7'},{8,'4','6','8'},{8,'4','6','9'},
        {8,'4','7','0'},{8,'4','7','1'},{8,'4','7','2'},{8,'4','7','3'},{8,'4','7','4'},
        {8,'4','7','5'},{8,'4','7','6'},{8,'4','7','7'},{8,'4','7','8'},{8,'4','7','9'},
        {8,'4','8','0'},{8,'4','8','1'},{8,'4','8','2'},{8,'4','8','3'},{8,'4','8','4'},
        {8,'4','8','5'},{8,'4','8','6'},{8,'4','8','7'},{8,'4','8','8'},{8,'4','8','9'},
        {8,'4','9','0'},{8,'4','9','1'},{8,'4','9','2'},{8,'4','9','3'},{8,'4','9','4'},
        {8,'4','9','5'},{8,'4','9','6'},{8,'4','9','7'},{8,'4','9','8'},{8,'4','9','9'},
        {8,'5','0','0'},{8,'5','0','1'},{8,'5','0','2'},{8,'5','0','3'},{8,'5','0','4'},
        {8,'5','0','5'},{8,'5','0','6'},{8,'5','0','7'},{8,'5','0','8'},{8,'5','0','9'},
        {8,'5','1','0'},{8,'5','1','1'},{8,'5','1','2'},{8,'5','1','3'},{8,'5','1','4'},
        {8,'5','1','5'},{8,'5','1','6'},{8,'5','1','7'},{8,'5','1','8'},{8,'5','1','9'},
        {8,'5','2','0'},{8,'5','2','1'},{8,'5','2','2'},{8,'5','2','3'},{8,'5','2','4'},
        {8,'5','2','5'},{8,'5','2','6'},{8,'5','2','7'},{8,'5','2','8'},{8,'5','2','9'},
        {8,'5','3','0'},{8,'5','3','1'},{8,'5','3','2'},{8,'5','3','3'},{8,'5','3','4'},
        {8,'5','3','5'},{8,'5','3','6'},{8,'5','3','7'},{8,'5','3','8'},{8,'5','3','9'},
        {8,'5','4','0'},{8,'5','4','1'},{8,'5','4','2'},{8,'5','4','3'},{8,'5','4','4'},
        {8,'5','4','5'},{8,'5','4','6'},{8,'5','4','7'},{8,'5','4','8'},{8,'5','4','9'},
        {8,'5','5','0'},{8,'5','5','1'},{8,'5','5','2'},{8,'5','5','3'},{8,'5','5','4'},
        {8,'5','5','5'},{8,'5','5','6'},{8,'5','5','7'},{8,'5','5','8'},{8,'5','5','9'},
        {8,'5','6','0'},{8,'5','6','1'},{8,'5','6','2'},{8,'5','6','3'},{8,'5','6','4'},
        {8,'5','6','5'},{8,'5','6','6'},{8,'5','6','7'},{8,'5','6','8'},{8,'5','6','9'},
        {8,'5','7','0'},{8,'5','7','1'},{8,'5','7','2'},{8,'5','7','3'},{8,'5','7','4'},
        {8,'5','7','5'},{8,'5','7','6'},{8,'5','7','7'},{8,'5','7','8'},{8,'5','7','9'},
        {8,'5','8','0'},{8,'5','8','1'},{8,'5','8','2'},{8,'5','8','3'},{8,'5','8','4'},
        {8,'5','8','5'},{8,'5','8','6'},{8,'5','8','7'},{8,'5','8','8'},{8,'5','8','9'},
        {8,'5','9','0'},{8,'5','9','1'},{8,'5','9','2'},{8,'5','9','3'},{8,'5','9','4'},
        {8,'5','9','5'},{8,'5','9','6'},{8,'5','9','7'},{8,'5','9','8'},{8,'5','9','9'},
        {8,'6','0','0'},{8,'6','0','1'},{8,'6','0','2'},{8,'6','0','3'},{8,'6','0','4'},
        {8,'6','0','5'},{8,'6','0','6'},{8,'6','0','7'},{8,'6','0','8'},{8,'6','0','9'},
        {8,'6','1','0'},{8,'6','1','1'},{8,'6','1','2'},{8,'6','1','3'},{8,'6','1','4'},
        {8,'6','1','5'},{8,'6','1','6'},{8,'6','1','7'},{8,'6','1','8'},{8,'6','1','9'},
        {8,'6','2','0'},{8,'6','2','1'},{8,'6','2','2'},{8,'6','2','3'},{8,'6','2','4'},
        {8,'6','2','5'},{8,'6','2','6'},{8,'6','2','7'},{8,'6','2','8'},{8,'6','2','9'},
        {8,'6','3','0'},{8,'6','3','1'},{8,'6','3','2'},{8,'6','3','3'},{8,'6','3','4'},
        {8,'6','3','5'},{8,'6','3','6'},{8,'6','3','7'},{8,'6','3','8'},{8,'6','3','9'},
        {8,'6','4','0'},{8,'6','4','1'},{8,'6','4','2'},{8,'6','4','3'},{8,'6','4','4'},
        {8,'6','4','5'},{8,'6','4','6'},{8,'6','4','7'},{8,'6','4','8'},{8,'6','4','9'},
        {8,'6','5','0'},{8,'6','5','1'},{8,'6','5','2'},{8,'6','5','3'},{8,'6','5','4'},
        {8,'6','5','5'},{8,'6','5','6'},{8,'6','5','7'},{8,'6','5','8'},{8,'6','5','9'},
        {8,'6','6','0'},{8,'6','6','1'},{8,'6','6','2'},{8,'6','6','3'},{8,'6','6','4'},
        {8,'6','6','5'},{8,'6','6','6'},{8,'6','6','7'},{8,'6','6','8'},{8,'6','6','9'},
        {8,'6','7','0'},{8,'6','7','1'},{8,'6','7','2'},{8,'6','7','3'},{8,'6','7','4'},
        {8,'6','7','5'},{8,'6','7','6'},{8,'6','7','7'},{8,'6','7','8'},{8,'6','7','9'},
        {8,'6','8','0'},{8,'6','8','1'},{8,'6','8','2'},{8,'6','8','3'},{8,'6','8','4'},
        {8,'6','8','5'},{8,'6','8','6'},{8,'6','8','7'},{8,'6','8','8'},{8,'6','8','9'},
        {8,'6','9','0'},{8,'6','9','1'},{8,'6','9','2'},{8,'6','9','3'},{8,'6','9','4'},
        {8,'6','9','5'},{8,'6','9','6'},{8,'6','9','7'},{8,'6','9','8'},{8,'6','9','9'},
        {8,'7','0','0'},{8,'7','0','1'},{8,'7','0','2'},{8,'7','0','3'},{8,'7','0','4'},
        {8,'7','0','5'},{8,'7','0','6'},{8,'7','0','7'},{8,'7','0','8'},{8,'7','0','9'},
        {8,'7','1','0'},{8,'7','1','1'},{8,'7','1','2'},{8,'7','1','3'},{8,'7','1','4'},
        {8,'7','1','5'},{8,'7','1','6'},{8,'7','1','7'},{8,'7','1','8'},{8,'7','1','9'},
        {8,'7','2','0'},{8,'7','2','1'},{8,'7','2','2'},{8,'7','2','3'},{8,'7','2','4'},
        {8,'7','2','5'},{8,'7','2','6'},{8,'7','2','7'},{8,'7','2','8'},{8,'7','2','9'},
        {8,'7','3','0'},{8,'7','3','1'},{8,'7','3','2'},{8,'7','3','3'},{8,'7','3','4'},
        {8,'7','3','5'},{8,'7','3','6'},{8,'7','3','7'},{8,'7','3','8'},{8,'7','3','9'},
        {8,'7','4','0'},{8,'7','4','1'},{8,'7','4','2'},{8,'7','4','3'},{8,'7','4','4'},
        {8,'7','4','5'},{8,'7','4','6'},{8,'7','4','7'},{8,'7','4','8'},{8,'7','4','9'},
        {8,'7','5','0'},{8,'7','5','1'},{8,'7','5','2'},{8,'7','5','3'},{8,'7','5','4'},
        {8,'7','5','5'},{8,'7','5','6'},{8,'7','5','7'},{8,'7','5','8'},{8,'7','5','9'},
        {8,'7','6','0'},{8,'7','6','1'},{8,'7','6','2'},{8,'7','6','3'},{8,'7','6','4'},
        {8,'7','6','5'},{8,'7','6','6'},{8,'7','6','7'},{8,'7','6','8'},{8,'7','6','9'},
        {8,'7','7','0'},{8,'7','7','1'},{8,'7','7','2'},{8,'7','7','3'},{8,'7','7','4'},
        {8,'7','7','5'},{8,'7','7','6'},{8,'7','7','7'},{8,'7','7','8'},{8,'7','7','9'},
        {8,'7','8','0'},{8,'7','8','1'},{8,'7','8','2'},{8,'7','8','3'},{8,'7','8','4'},
        {8,'7','8','5'},{8,'7','8','6'},{8,'7','8','7'},{8,'7','8','8'},{8,'7','8','9'},
        {8,'7','9','0'},{8,'7','9','1'},{8,'7','9','2'},{8,'7','9','3'},{8,'7','9','4'},
        {8,'7','9','5'},{8,'7','9','6'},{8,'7','9','7'},{8,'7','9','8'},{8,'7','9','9'},
        {8,'8','0','0'},{8,'8','0','1'},{8,'8','0','2'},{8,'8','0','3'},{8,'8','0','4'},
        {8,'8','0','5'},{8,'8','0','6'},{8,'8','0','7'},{8,'8','0','8'},{8,'8','0','9'},
        {8,'8','1','0'},{8,'8','1','1'},{8,'8','1','2'},{8,'8','1','3'},{8,'8','1','4'},
        {8,'8','1','5'},{8,'8','1','6'},{8,'8','1','7'},{8,'8','1','8'},{8,'8','1','9'},
        {8,'8','2','0'},{8,'8','2','1'},{8,'8','2','2'},{8,'8','2','3'},{8,'8','2','4'},
        {8,'8','2','5'},{8,'8','2','6'},{8,'8','2','7'},{8,'8','2','8'},{8,'8','2','9'},
        {8,'8','3','0'},{8,'8','3','1'},{8,'8','3','2'},{8,'8','3','3'},{8,'8','3','4'},
        {8,'8','3','5'},{8,'8','3','6'},{8,'8','3','7'},{8,'8','3','8'},{8,'8','3','9'},
        {8,'8','4','0'},{8,'8','4','1'},{8,'8','4','2'},{8,'8','4','3'},{8,'8','4','4'},
        {8,'8','4','5'},{8,'8','4','6'},{8,'8','4','7'},{8,'8','4','8'},{8,'8','4','9'},
        {8,'8','5','0'},{8,'8','5','1'},{8,'8','5','2'},{8,'8','5','3'},{8,'8','5','4'},
        {8,'8','5','5'},{8,'8','5','6'},{8,'8','5','7'},{8,'8','5','8'},{8,'8','5','9'},
        {8,'8','6','0'},{8,'8','6','1'},{8,'8','6','2'},{8,'8','6','3'},{8,'8','6','4'},
        {8,'8','6','5'},{8,'8','6','6'},{8,'8','6','7'},{8,'8','6','8'},{8,'8','6','9'},
        {8,'8','7','0'},{8,'8','7','1'},{8,'8','7','2'},{8,'8','7','3'},{8,'8','7','4'},
        {8,'8','7','5'},{8,'8','7','6'},{8,'8','7','7'},{8,'8','7','8'},{8,'8','7','9'},
        {8,'8','8','0'},{8,'8','8','1'},{8,'8','8','2'},{8,'8','8','3'},{8,'8','8','4'},
        {8,'8','8','5'},{8,'8','8','6'},{8,'8','8','7'},{8,'8','8','8'},{8,'8','8','9'},
        {8,'8','9','0'},{8,'8','9','1'},{8,'8','9','2'},{8,'8','9','3'},{8,'8','9','4'},
        {8,'8','9','5'},{8,'8','9','6'},{8,'8','9','7'},{8,'8','9','8'},{8,'8','9','9'},
        {8,'9','0','0'},{8,'9','0','1'},{8,'9','0','2'},{8,'9','0','3'},{8,'9','0','4'},
        {8,'9','0','5'},{8,'9','0','6'},{8,'9','0','7'},{8,'9','0','8'},{8,'9','0','9'},
        {8,'9','1','0'},{8,'9','1','1'},{8,'9','1','2'},{8,'9','1','3'},{8,'9','1','4'},
        {8,'9','1','5'},{8,'9','1','6'},{8,'9','1','7'},{8,'9','1','8'},{8,'9','1','9'},
        {8,'9','2','0'},{8,'9','2','1'},{8,'9','2','2'},{8,'9','2','3'},{8,'9','2','4'},
        {8,'9','2','5'},{8,'9','2','6'},{8,'9','2','7'},{8,'9','2','8'},{8,'9','2','9'},
        {8,'9','3','0'},{8,'9','3','1'},{8,'9','3','2'},{8,'9','3','3'},{8,'9','3','4'},
        {8,'9','3','5'},{8,'9','3','6'},{8,'9','3','7'},{8,'9','3','8'},{8,'9','3','9'},
        {8,'9','4','0'},{8,'9','4','1'},{8,'9','4','2'},{8,'9','4','3'},{8,'9','4','4'},
        {8,'9','4','5'},{8,'9','4','6'},{8,'9','4','7'},{8,'9','4','8'},{8,'9','4','9'},
        {8,'9','5','0'},{8,'9','5','1'},{8,'9','5','2'},{8,'9','5','3'},{8,'9','5','4'},
        {8,'9','5','5'},{8,'9','5','6'},{8,'9','5','7'},{8,'9','5','8'},{8,'9','5','9'},
        {8,'9','6','0'},{8,'9','6','1'},{8,'9','6','2'},{8,'9','6','3'},{8,'9','6','4'},
        {8,'9','6','5'},{8,'9','6','6'},{8,'9','6','7'},{8,'9','6','8'},{8,'9','6','9'},
        {8,'9','7','0'},{8,'9','7','1'},{8,'9','7','2'},{8,'9','7','3'},{8,'9','7','4'},
        {8,'9','7','5'},{8,'9','7','6'},{8,'9','7','7'},{8,'9','7','8'},{8,'9','7','9'},
        {8,'9','8','0'},{8,'9','8','1'},{8,'9','8','2'},{8,'9','8','3'},{8,'9','8','4'},
        {8,'9','8','5'},{8,'9','8','6'},{8,'9','8','7'},{8,'9','8','8'},{8,'9','8','9'},
        {8,'9','9','0'},{8,'9','9','1'},{8,'9','9','2'},{8,'9','9','3'},{8,'9','9','4'},
        {8,'9','9','5'},{8,'9','9','6'},{8,'9','9','7'},{8,'9','9','8'},{8,'9','9','9'},
    };
    __attribute__((used)) unsigned const n1000 = 1000;
    __attribute__((used)) unsigned const n1000000 = 1000000;
    __attribute__((used)) unsigned const n1000000000 = 1000000000;
    
    inline void itostr(char* buf, unsigned v)
    {
        unsigned a,b;
        asm volatile
        (
            "xorl   %%edx, %%edx\n\t"
            "cmpl   $1000000, %%eax\n\t"     // >= 1.000.000 ?
            "jnb    1f\n\t"
            "cmpl   $1000, %%eax\n\t"        // >= 1.000 ?
            "jnb    2f\n\t"
            "movl   _lookup(,%%eax,4), %%ecx\n\t"
            "shrl   %%cl, %%ecx\n\t"
            "movl   %%ecx, (%%ebx)\n\t"
            "jmp    0f\n\t"
            "2:\n\t"                        // 1.000 <= v < 1.000.000
            "divl   _n1000\n\t"
            "movl   _lookup(,%%eax,4), %%eax\n\t"
            "movzbl %%al, %%ecx\n\t"
            "movl   _lookup+1(,%%edx,4), %%edx\n\t"
            "shrl   %%cl, %%eax\n\t"
            "shrl   $3, %%ecx\n\t"
            "neg    %%ecx\n\t"
            "movl   %%eax, (%%ebx)\n\t"
            "andl   $0x00ffffff, %%edx\n\t"
            "movl   %%edx, 4(%%ebx,%%ecx,1)\n\t"
            "jmp    0f\n\t"
            "1:\n\t"                        // v >= 1.000.000
            "cmpl   $1000000000, %%eax\n\t" // >= 1.000.000.000 ?
            "jnb    3f\n\t"
            "divl   _n1000000\n\t"
            "movl   _lookup(,%%eax,4), %%eax\n\t"
            "movzbl %%al, %%ecx\n\t"
            "shrl   %%cl, %%eax\n\t"
            "shrl   $3, %%ecx\n\t"
            "movl   %%eax, (%%ebx)\n\t"
            "subl   %%ecx, %%ebx\n\t"
            "movl   %%edx, %%eax\n\t"
            "xorl   %%edx, %%edx\n\t"
            "divl   _n1000\n\t"
            "movl   _lookup+1(,%%eax,4), %%eax\n\t"
            "movl   _lookup+1(,%%edx,4), %%edx\n\t"
            "andl   $0x00ffffff, %%edx\n\t"
            "movl   %%eax, 4(%%ebx)\n\t"
            "movl   %%edx, 7(%%ebx)\n\t"
            "jmp    0f\n\t"
            "3:\n\t"                        // v >= 1.000.000.000
            "divl   _n1000000000\n\t"
            "addl   $0x30, %%eax\n\t"
            "movl   %%eax, (%%ebx)\n\t"
            "movl   %%edx, %%eax\n\t"
            "xorl   %%edx, %%edx\n\t"
            "divl   _n1000000\n\t"
            "movl   _lookup+1(,%%eax,4), %%ecx\n\t"
            "movl   %%edx, %%eax\n\t"
            "xorl   %%edx, %%edx\n\t"
            "divl   _n1000\n\t"
            "movl   _lookup+1(,%%eax,4), %%eax\n\t"
            "movl   _lookup+1(,%%edx,4), %%edx\n\t"
            "movl   %%ecx, 1(%%ebx)\n\t"
            "andl   $0x00ffffff, %%edx\n\t"
            "movl   %%eax, 4(%%ebx)\n\t"
            "movl   %%edx, 7(%%ebx)\n\t"
            "0:\n\t"
            : "=b" ( b ), "=a" ( a )
            : "b" ( buf ), "a" ( v )
            : "ecx", "edx"
        );
    }
    #include <iostream>
    typedef unsigned long long u64;
    inline u64 rdtsc()
    {
        u64 result;
        asm volatile ( "rdtsc" : "=A" (result) );
        return result;
    }
    int main()
    {
        u64 gtime;
        char xyz[10] = "";
        gtime = rdtsc();
        for(unsigned i = 0; i < ~0u; ++i )
        {
            itostr(xyz,i);
        }
        gtime = rdtsc() - gtime;
        std::cout << gtime << '\t' << double(gtime)/4294967295.0 << std::endl;
        return 0;
    }
    


  • re

    😃 sehr nett der source

    koentest da mal auch ne durchlaufszeit mit angeben ? ich glaub weniger, das ich das 1:1 uebernehmen koennen werde.

    werd das auch mal mit ner 1000er table probieren.
    is das AT&T syntax ?

    Meep Meep


Anmelden zum Antworten