Перевод строки в 64 бит целое
От: Аноним  
Дата: 21.02.08 18:02
Оценка:
Нужен перевод строки в 64 бит целое. Компилятор поддерживает только 32 бит целые числа, поэтому на выходе нужен просто массив байт. Киньте пожалуйста алгоритм или ссылку кто знает.
Re: Перевод строки в 64 бит целое
От: Аноним  
Дата: 22.02.08 11:17
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Нужен перевод строки в 64 бит целое. Компилятор поддерживает только 32 бит целые числа, поэтому на выходе нужен просто массив байт. Киньте пожалуйста алгоритм или ссылку кто знает.


Думаю многие знают, но лень Вот тебе примерчег:
#include <malloc.h>

void throw_overflow() { throw "ints overflow"; }
void throw_bad_syntax() { throw "invalid syntax"; }
#define stack_alloc(n,t) (t*)alloca(n*sizeof(t))

typedef unsigned uint;
const uint uint_bits=8*sizeof(uint);
const uint last_bit =1<<(uint_bits-1);
const uint uint_max =~0;
const uint mask_nlb =~last_bit;

int get_add_carry(uint a,uint b,uint c=0) {
    int cc=0;
    if (a&last_bit) ++cc;
    if (b&last_bit) ++cc;
    a&=mask_nlb; b&=mask_nlb;
    if ((a+b+c)&last_bit) ++cc;
    return cc>1;
}
void ints_clr(int n,uint *r)         { for(int i=0;i<n;i++) r[i]=0; }
void ints_mov(int n,uint *r,uint *a) { for(int i=0;i<n;i++) r[i]=a[i]; }
void ints_movzx(int n,uint *r,int a) { r[0]=(uint)a; for(int i=1;i<n;i++) r[i]=0; }
uint ints_addzx(int n,uint *r,uint *a,uint b,uint c=0) {
    int cc=get_add_carry(a[0],b,c); r[0]=a[0]+b+c; c=cc;
    for(int i=1;c && i<n;i++) { c=(a[i]==uint_max); r[i]=a[i]+1; }
    return c;
}
uint ints_add(int n,uint *r,uint *a,uint *b,uint c=0) {
    for(int i=0;i<n;i++) { int cc=get_add_carry(a[i],b[i],c); r[i]=a[i]+b[i]+c; c=cc; }
    return c;
}
void ints_mul10(int n,uint *x) {
    uint *t=stack_alloc(n,uint);
    uint c1=ints_add(n,t,x,x); 
    ints_mov(n,x,t);   
    c1+=ints_add(n,t,t,t); 
    c1+=ints_add(n,t,t,t); 
    c1+=ints_add(n,x,x,t); 
    if (c1>0) throw_overflow();
}
int is_space(char c) { return c>0 && c<=32; }
int is_digit(char c) { return c>='0' && c<='9'; }
int ints_ldstr(int n,uint *x,const char* s) {
    ints_clr(n,x);
    int p=0;while(is_space(s[p])) p++;
    if (!is_digit(s[p])) throw_bad_syntax();
    ints_movzx(n,x,s[p++]-'0');
    while(is_digit(s[p])) {
        ints_mul10(n,x);
        if (ints_addzx(n,x,x,s[p]-'0')) throw_overflow();
        p++;
    }
    return p;
}

// тест на вшивость
#include <iostream>
using namespace std;

typedef long long int64; // gcc
//typedef __int64 int64; // vc

int main(int argc, const char **argv) {
    int64 x; int n=sizeof(x)/sizeof(uint);
    ints_ldstr(n,(uint*)&x,"1234567890123456789"); cout<<x<<endl;
    x=1234567890123456789LL; cout<<x<<endl;
    return 0;
}


ps: к сожалению перенос от сложения в C/C++ не задуман, так что get_add_carry это костыль. на асме всё гораздо приятнее смотрится
Re[2]: небольшая оптимизация
От: Аноним  
Дата: 22.02.08 11:30
Оценка:
Здравствуйте, Аноним, Вы писали:

Вот немного оптимизированный вариант *10: на одну операцию меньше
void ints_mul10(int n,uint *x) {
    uint *t=stack_alloc(n,uint),
     c=ints_add(n,x,x,x);
    c+=ints_add(n,t,x,x);
    c+=ints_add(n,t,t,t);
    c+=ints_add(n,x,x,t);
    if (c) throw_overflow();
}
Re[2]: Перевод строки в 64 бит целое
От: xscream Россия  
Дата: 22.02.08 17:09
Оценка:
А>Думаю многие знают, но лень Вот тебе примерчег:

Спасибо, вот еще вариант:


    char str[] = "12345678901234567890"; // строка на входе 
    unsigned char uc[8]; // массив на выходе

    unsigned long l = 0;
    unsigned long m = 0;
    unsigned long h = 0;
    unsigned char carry;

    for( char *c = str; *c; c++ )
    {
        l += *c - '0';
        if( *(c + 1) )
        {
            l *= 10;
            carry = (unsigned char)((l & 0xFF000000) >> 24);
            l &= 0x00FFFFFF;
            m *= 10;
            m += carry;
            carry = (unsigned char)((m & 0xFF000000) >> 24);
            m &= 0x00FFFFFF;
            h *= 10;
            h += carry;
        }
    }

    uc[7] = (unsigned char)l; l >>= 8;
    uc[6] = (unsigned char)l; l >>= 8;
    uc[5] = (unsigned char)l;

    uc[4] = (unsigned char)m; m >>= 8;
    uc[3] = (unsigned char)m; m >>= 8;
    uc[2] = (unsigned char)m;

    uc[1] = (unsigned char)h; h >>= 8;
    uc[0] = (unsigned char)h;
Re[3]: Перевод строки в 64 бит целое
От: Аноним  
Дата: 22.02.08 21:12
Оценка:
Здравствуйте, xscream, Вы писали:

А>>Думаю многие знают, но лень Вот тебе примерчег:


X>Спасибо, вот еще вариант:


Не буду хвастаться, но замечу что у меня есть проверка на переполнение и возможность работать int128, int256 и т.д.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.