簡體   English   中英

8字節雙精度數作為uint64_t的二進制字符串

[英]8 byte double as binary string to uint64_t

我正在尋找將8字節雙精度轉換為uint64_t的方法。 我不能使用任何標准庫,因為在我的解決方案中只有4byte的兩倍。

此轉換應將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)時,它將返回10225202(應為10225203)

您能以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”。

/*
*  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);
}

您可以修改此功能以執行所需的操作。

https://github.com/MalcolmMcLean/ieee754

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM