2016-10-07 16 views
2

8バイトのdoubleをuint64_tに変換する方法を探しています。私の解決策では4byteしかないので、標準ライブラリを使用することはできません。8バイトの倍精度文字列をuint64_tに変換

この変換では、10987789.5から10987789をintに変換する必要があります。私が今使っ

変換:

uint64_t binDoubleToUint64_t(char *bit){ 
    uint8_t i, j; 
    uint64_t fraction; 
    for(i=0; i<64; i++) 
     bit[i]-='0'; 

    uint16_t exponent = bit[1] ? 1 : 0; 

    j = 0; 
    for(i=9; i>0;i--) 
     exponent += bit[i+2] * int_pow(2, j++); 

    bit[11] = bit[1]; 
    fraction = 0; 
    j=0; 

    for(i=0; i < exponent; i++){ 
     fraction = fraction << 1; 
     if(bit[11+i]) 
     fraction |= 1 << 1; 
    } 
    return fraction; 
} 

しかし、これは私に間違った答えを与えます。私は、二重10225203.0(0x416380c660000000)を変換しようとする一方で それはあなたが自明あなたが欲しいものを行うには、この機能を変更することができ

答えて

2

あなたはまっすぐuint64_tとしてのビット値を読み取ることができます。あなたが与えられた値をチェックすることもできますので、

これは、浮動小数点の仕様の私の記憶から書き込まれた
uint64_t binDoubleToUint64_t (uint64_t in) { 
    if (!(in & 0x4000000000000000) || in & 0x800000000000000000) { 
    /* If the exponent isn't big enough to give a value greater than 1 
    * or our number is negative return 0. 
    */ 
    return 0; 
    } 

    uint32_t exponent = ((in & 0x7FF0000000000000) >> 52) - 1023; 

    // get the mantissa including the imagined bit. 
    uint64_t mantissa = (in & 0xFFFFFFFFFFFFF) | 0x10000000000000; 

    // Now we just need to work out how much to shift the mantissa by. 
    /* You may notice that the top bit of the mantissa is actually at 53 once 
    you put the imagined bit back in, mantissaTopBit is really 
    floor(log2(mantissa)) which is 52 (i.e. the power of 2 of the position 
    that the top bit is in). I couldn't think of a good name for this, so just 
    imagine that you started counting from 0 instead of 1 if you like! 
    */ 
    uint32_t mantissaTopBit = 52; 

    if (mantissaTopBit > exponent) 
    return mantissa >> mantissaTopBit - exponent; 
    else { 
    if (exponent - mantissaTopBit > 12) { 
     //You're in trouble as your double doesn't fit into an uint64_t 
    } 

    return mantissa << exponent - mantissaTopBit; 
    } 
} 

(私はすべての値をチェックしていない):次に、コードは次のようになります。これはあなたの例では機能しますが、私はどこにいても正しい数の '0'を入れたことを確認したいかもしれません。

+0

あなたは基本的に正しい行にあります。しかしIEEE 754には、無限大、非正規化数、NaNなどの特殊なケースがたくさんあります。 –

+0

@MalcolmMcLeanメモリが正しく機能するならば、これらはほとんど全てが最初のテストで捕捉され、指数部のサイズに関するテストは指数部に特別な値が必要です。おそらく-0を除いて特殊なケースにする必要があるかもしれません。 –

+0

私の場合、これはすべての値を渡します。この答えは本当に良いです。ありがとう:)私はそれをテストし、私のコードで使用します。 – Sahee

1
/* 
* write a double to a stream in ieee754 format regardless of host 
* encoding. 
* x - number to write 
* fp - the stream 
* bigendian - set to write big bytes first, else write little bytes first 
* Returns: 0 or EOF on error 
* Notes: different NaN types and negative zero not preserved. 
*   if the number is too big to represent it will become infinity 
*   if it is too small to represent it will become zero. 
*/ 
int fwriteieee754(double x, FILE *fp, int bigendian) 
{ 
    int shift; 
    unsigned long sign, exp, hibits, hilong, lowlong; 
    double fnorm, significand; 
    int expbits = 11; 
    int significandbits = 52; 

    /* zero (can't handle signed zero) */ 
    if (x == 0) 
    { 
     hilong = 0; 
     lowlong = 0; 
     goto writedata; 
    } 
    /* infinity */ 
    if (x > DBL_MAX) 
    { 
     hilong = 1024 + ((1 << (expbits - 1)) - 1); 
     hilong <<= (31 - expbits); 
     lowlong = 0; 
     goto writedata; 
    } 
    /* -infinity */ 
    if (x < -DBL_MAX) 
    { 
     hilong = 1024 + ((1 << (expbits - 1)) - 1); 
     hilong <<= (31 - expbits); 
     hilong |= (1 << 31); 
     lowlong = 0; 
     goto writedata; 
    } 
    /* NaN - dodgy because many compilers optimise out this test, but 
    *there is no portable isnan() */ 
    if (x != x) 
    { 
     hilong = 1024 + ((1 << (expbits - 1)) - 1); 
     hilong <<= (31 - expbits); 
     lowlong = 1234; 
     goto writedata; 
    } 

    /* get the sign */ 
    if (x < 0) { sign = 1; fnorm = -x; } 
    else { sign = 0; fnorm = x; } 

    /* get the normalized form of f and track the exponent */ 
    shift = 0; 
    while (fnorm >= 2.0) { fnorm /= 2.0; shift++; } 
    while (fnorm < 1.0) { fnorm *= 2.0; shift--; } 

    /* check for denormalized numbers */ 
    if (shift < -1022) 
    { 
     while (shift < -1022) { fnorm /= 2.0; shift++; } 
     shift = -1023; 
    } 
    /* out of range. Set to infinity */ 
    else if (shift > 1023) 
    { 
     hilong = 1024 + ((1 << (expbits - 1)) - 1); 
     hilong <<= (31 - expbits); 
     hilong |= (sign << 31); 
     lowlong = 0; 
     goto writedata; 
    } 
    else 
     fnorm = fnorm - 1.0; /* take the significant bit off mantissa */ 

    /* calculate the integer form of the significand */ 
    /* hold it in a double for now */ 

    significand = fnorm * ((1LL << significandbits) + 0.5f); 


    /* get the biased exponent */ 
    exp = shift + ((1 << (expbits - 1)) - 1); /* shift + bias */ 

    /* put the data into two longs (for convenience) */ 
    hibits = (long)(significand/4294967296); 
    hilong = (sign << 31) | (exp << (31 - expbits)) | hibits; 
    x = significand - hibits * 4294967296; 
    lowlong = (unsigned long)(significand - hibits * 4294967296); 

writedata: 
    /* write the bytes out to the stream */ 
    if (bigendian) 
    { 
     fputc((hilong >> 24) & 0xFF, fp); 
     fputc((hilong >> 16) & 0xFF, fp); 
     fputc((hilong >> 8) & 0xFF, fp); 
     fputc(hilong & 0xFF, fp); 

     fputc((lowlong >> 24) & 0xFF, fp); 
     fputc((lowlong >> 16) & 0xFF, fp); 
     fputc((lowlong >> 8) & 0xFF, fp); 
     fputc(lowlong & 0xFF, fp); 
    } 
    else 
    { 
     fputc(lowlong & 0xFF, fp); 
     fputc((lowlong >> 8) & 0xFF, fp); 
     fputc((lowlong >> 16) & 0xFF, fp); 
     fputc((lowlong >> 24) & 0xFF, fp); 

     fputc(hilong & 0xFF, fp); 
     fputc((hilong >> 8) & 0xFF, fp); 
     fputc((hilong >> 16) & 0xFF, fp); 
     fputc((hilong >> 24) & 0xFF, fp); 
    } 
    return ferror(fp); 
} 

10225202(はず10225203)を返します。

https://github.com/MalcolmMcLean/ieee754

+0

いくつかは、downvotesを説明することができますか? –

関連する問題