C语言 无需 sprintf() 即可将浮点数转换为字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23191203/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 11:01:57  来源:igfitidea点击:

Convert float to string without sprintf()

cstringmemoryfloating-pointprintf

提问by audiFanatic

I'm coding for a microcontroller-based application and I need to convert a floatto a character string, but I do not need the heavy overhead associated with sprintf(). Is there any eloquent way to do this? I don't need too much. I only need 2 digits of precision.

我正在为基于微控制器的应用程序编码,我需要将 a 转换为float字符串,但我不需要与 sprintf() 相关的大量开销。有没有雄辩的方法来做到这一点?我不需要太多。我只需要 2 位数的精度。

采纳答案by enhzflep

Try this. It should be nice and small. I've output the string directly - doing a printf, rather than a sprintf. I'll leave it to you to allocate space for the return string, as well as copying the result into it.

尝试这个。它应该很好而且很小。我直接输出了字符串——做一个 printf,而不是一个 sprintf。我会让你为返回字符串分配空间,以及将结果复制到其中。

// prints a number with 2 digits following the decimal place
// creates the string backwards, before printing it character-by-character from
// the end to the start
//
// Usage: myPrintf(270.458)
//  Output: 270.45
void myPrintf(float fVal)
{
    char result[100];
    int dVal, dec, i;

    fVal += 0.005;   // added after a comment from Matt McNabb, see below.

    dVal = fVal;
    dec = (int)(fVal * 100) % 100;

    memset(result, 0, 100);
    result[0] = (dec % 10) + '0';
    result[1] = (dec / 10) + '0';
    result[2] = '.';

    i = 3;
    while (dVal > 0)
    {
        result[i] = (dVal % 10) + '0';
        dVal /= 10;
        i++;
    }

    for (i=strlen(result)-1; i>=0; i--)
        putc(result[i], stdout);
}

回答by Escher

Here's a version optimized for embedded systems that doesn't require any stdio or memset, and has low memory footprint. You're responsible for passing a char buffer initialized with zeros (with pointer p) where you want to store your string, and defining CHAR_BUFF_SIZEwhen you make said buffer (so the returned string will be null terminated).

这是一个针对嵌入式系统优化的版本,它不需要任何 stdio 或 memset,并且具有低内存占用。您负责传递一个用零初始化的字符缓冲区(带有指针p),您想在其中存储字符串,并定义CHAR_BUFF_SIZE何时创建所述缓冲区(因此返回的字符串将以空值终止)。

static char * _float_to_char(float x, char *p) {
    char *s = p + CHAR_BUFF_SIZE; // go to end of buffer
    uint16_t decimals;  // variable to store the decimals
    int units;  // variable to store the units (part to left of decimal place)
    if (x < 0) { // take care of negative numbers
        decimals = (int)(x * -100) % 100; // make 1000 for 3 decimals etc.
        units = (int)(-1 * x);
    } else { // positive numbers
        decimals = (int)(x * 100) % 100;
        units = (int)x;
    }

    *--s = (decimals % 10) + '0';
    decimals /= 10; // repeat for as many decimal places as you need
    *--s = (decimals % 10) + '0';
    *--s = '.';

    while (units > 0) {
        *--s = (units % 10) + '0';
        units /= 10;
    }
    if (x < 0) *--s = '-'; // unary minus sign for negative numbers
    return s;
}

Tested on ARM Cortex M0 & M4. Rounds correctly.

在 ARM Cortex M0 和 M4 上测试。正确绕圈。

回答by Petrus

I can't comment on enhzflep's response, but to handle negative numbers correctly (which the current version does not), you only need to add

我无法评论 enhzflep 的回应,但要正确处理负数(当前版本没有),您只需要添加

if (fVal < 0) {
     putc('-', stdout);
     fVal = -fVal;
  }

at the beginning of the function.

在函数的开头。

回答by Chaithra

// convert float to string one decimal digit at a time
// assumes float is < 65536 and ARRAYSIZE is big enough
// problem: it truncates numbers at size without rounding
// str is a char array to hold the result, float is the number to convert
// size is the number of decimal digits you want


void FloatToStringNew(char *str, float f, char size)

{

char pos;  // position in string

    char len;  // length of decimal part of result

    char* curr;  // temp holder for next digit

    int value;  // decimal digit(s) to convert

    pos = 0;  // initialize pos, just to be sure

    value = (int)f;  // truncate the floating point number
    itoa(value,str);  // this is kinda dangerous depending on the length of str
    // now str array has the digits before the decimal

    if (f < 0 )  // handle negative numbers
    {
        f *= -1;
        value *= -1;
    }

     len = strlen(str);  // find out how big the integer part was
    pos = len;  // position the pointer to the end of the integer part
    str[pos++] = '.';  // add decimal point to string

    while(pos < (size + len + 1) )  // process remaining digits
    {
        f = f - (float)value;  // hack off the whole part of the number
        f *= 10;  // move next digit over
        value = (int)f;  // get next digit
        itoa(value, curr); // convert digit to string
        str[pos++] = *curr; // add digit to result string and increment pointer
    }
 }

回答by audiFanatic

While you guys were answering I've come up with my own solution which that works better for my application and I figure I'd share. It doesn't convert the float to a string, but rather 8-bit integers. My range of numbers is very small (0-15) and always non-negative, so this will allow me to send the data over bluetooth to my android app.

当你们回答时,我想出了我自己的解决方案,它更适合我的应用程序,我想我会分享。它不会将浮点数转换为字符串,而是将 8 位整数。我的数字范围非常小(0-15)并且始终为非负数,因此这将允许我通过蓝牙将数据发送到我的 android 应用程序。

//Assumes bytes* is at least 2-bytes long
void floatToBytes(byte_t* bytes, float flt)
{
  bytes[1] = (byte_t) flt;    //truncate whole numbers
  flt = (flt - bytes[1])*100; //remove whole part of flt and shift 2 places over
  bytes[0] = (byte_t) flt;    //truncate the fractional part from the new "whole" part
}
//Example: 144.2345 -> bytes[1] = 144; -> bytes[0] = 23

回答by Sumir Kumar Jha

Its a Liitle large method, but It would work for both int and float, decimalPoint parameter is passed with zero value for Integer, Please let me know if you have smaller function than this.

它是一个小大方法,但它适用于 int 和 float,decimalPoint 参数传递给整数的零值,如果你有比这更小的函数,请告诉我。

void floatToStr(uint8_t *out, float x,int decimalPoint)
{
    uint16_t absval = fabs(x);
    uint16_t absvalcopy = absval;


    int decimalcount = 0;

    while(absvalcopy != 0)
    {

        absvalcopy /= 10;
        decimalcount ++;
    }

    uint8_t *absbuffer = malloc(sizeof(uint8_t) * (decimalcount + decimalPoint + 1));
    int absbufferindex = 0;
    absvalcopy = absval;
    uint8_t temp;

    int i = 0;
    for(i = decimalcount; i > 0; i--)
    {
        uint16_t frst1 = fabs((absvalcopy / pow(10.0, i-1)));
        temp = (frst1 % 10) + 0x30;
        *(absbuffer + absbufferindex) = temp;
        absbufferindex++;
    }

    if(decimalPoint > 0)
    {
        *(absbuffer + absbufferindex) = '.';
        absbufferindex ++;

        //------------------- Decimal Extractor ---------------------//
       for(i = 1; i < decimalPoint + 1; i++)
       {

           uint32_t valueFloat = (x - (float)absval)*pow(10,i);
           *(absbuffer + absbufferindex) = ((valueFloat) % 10) + 0x30;
           absbufferindex++;
       }
    }

   for(i=0; i< (decimalcount + decimalPoint + 1); i++)
   {
       *(out + i) = *(absbuffer + i);
   }

   i=0;
   if(decimalPoint > 0)
       i = 1;
   *(out + decimalcount + decimalPoint + i) = 0;

}