Add Hexadecimal parsing for strtof

solve:
  almost the Hexadecimal string string->float
such as:
  code:float num;
       const char *s= "0x123p32lala";
       char *p;
       num=strtof(s,&p);
       printf("num is %f\n",num);
       printf("str is %s\n",p);
  output:num is 1249835483136.000000
         str is lala

but if the input number is much big;
like:
  code:const char *s2= "0x999999p100";
       num=strtof(s2,&p);
       printf("num is %f\n",num);
       printf("str is %s\n",p);
  corrent : num is 12760587998944832242938906880669384704.000000
  real:     num is 12760587998944800000000000000000000000.000000
it didn't have enough precision
This commit is contained in:
flyingfish89 2022-11-28 22:38:22 +08:00 committed by Xiang Xiao
parent 4281acdb83
commit fa59db8cea
2 changed files with 124 additions and 14 deletions

View file

@ -44,6 +44,8 @@
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#ifdef CONFIG_HAVE_DOUBLE
/****************************************************************************
@ -80,6 +82,36 @@ static inline int is_real(double x)
return (x < infinite) && (x >= -infinite);
}
static bool chtod(char c, double base, FAR double *number)
{
/* This function is to determine if c is keyword
* Then set number + base
*/
double tmp = base;
if (isdigit(c))
{
tmp = c - '0';
}
else if (c >= 'a' && c <= 'f')
{
tmp = c - 'a' + 10;
}
else if (c >= 'A' && c <= 'F')
{
tmp = c - 'A' + 10;
}
if (tmp >= base)
{
return false;
}
*number = *number * base + tmp;
return true;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -140,16 +172,24 @@ double strtod(FAR const char *str, FAR char **endptr)
break;
}
p10 = 10.;
number = 0.;
exponent = 0;
num_digits = 0;
num_decimals = 0;
/* Process optional 0x prefix */
if (*p == '0' && tolower(*(p + 1)) == 'x')
{
p += 2;
p10 = 16.;
}
/* Process string of digits */
while (isdigit(*p))
while (chtod(*p, p10, &number))
{
number = number * 10. + (*p - '0');
p++;
num_digits++;
}
@ -160,9 +200,8 @@ double strtod(FAR const char *str, FAR char **endptr)
{
p++;
while (isdigit(*p))
while (chtod(*p, p10, &number))
{
number = number * 10. + (*p - '0');
p++;
num_digits++;
num_decimals++;
@ -188,8 +227,17 @@ double strtod(FAR const char *str, FAR char **endptr)
/* Process an exponent string */
if (*p == 'e' || *p == 'E')
if ((p10 == 10. && (*p == 'e' || *p == 'E'))
|| (p10 == 16. && (*p == 'p' || *p == 'P')))
{
/* if the Hexadecimal system */
if (p10 == 16.)
{
exponent *= 4;
p10 = 2.0;
}
/* Handle optional sign */
negative = 0;
@ -240,13 +288,20 @@ double strtod(FAR const char *str, FAR char **endptr)
exponent > __DBL_MAX_EXP__)
{
set_errno(ERANGE);
number = infinite;
if (exponent < __DBL_MIN_EXP__)
{
number = divzero;
}
else
{
number = infinite;
}
goto errout;
}
/* Scale the result */
p10 = 10.;
n = exponent;
if (n < 0)
{

View file

@ -48,6 +48,8 @@
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
/****************************************************************************
* Pre-processor definitions
****************************************************************************/
@ -82,6 +84,36 @@ static inline int is_real(float x)
return (x < infinite) && (x >= -infinite);
}
static bool chtof(char c, float base, FAR float *number)
{
/* This function is to determine if c is keyword
* Then set number + base
*/
float tmp = base;
if (isdigit(c))
{
tmp = c - '0';
}
else if (c >= 'a' && c <= 'f')
{
tmp = c - 'a' + 10;
}
else if (c >= 'A' && c <= 'F')
{
tmp = c - 'A' + 10;
}
if (tmp >= base)
{
return false;
}
*number = *number * base + tmp;
return true;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -142,16 +174,24 @@ float strtof(FAR const char *str, FAR char **endptr)
break;
}
p10 = 10.0f;
number = 0.0F;
exponent = 0;
num_digits = 0;
num_decimals = 0;
/* Process optional 0x prefix */
if (*p == '0' && tolower(*(p + 1)) == 'x')
{
p += 2;
p10 = 16.0f;
}
/* Process string of digits */
while (isdigit(*p))
while (chtof(*p, p10, &number))
{
number = number * 10.0F + (float)(*p - '0');
p++;
num_digits++;
}
@ -162,9 +202,8 @@ float strtof(FAR const char *str, FAR char **endptr)
{
p++;
while (isdigit(*p))
while (chtof(*p, p10, &number))
{
number = number * 10.0F + (float)(*p - '0');
p++;
num_digits++;
num_decimals++;
@ -190,8 +229,17 @@ float strtof(FAR const char *str, FAR char **endptr)
/* Process an exponent string */
if (*p == 'e' || *p == 'E')
if ((p10 == 10.0f && (*p == 'e' || *p == 'E'))
|| (p10 == 16.0f && (*p == 'p' || *p == 'P')))
{
/* if the Hexadecimal system */
if (p10 == 16.0f)
{
exponent *= 4;
p10 = 2.0f;
}
/* Handle optional sign */
negative = 0;
@ -242,13 +290,20 @@ float strtof(FAR const char *str, FAR char **endptr)
exponent > __FLT_MAX_EXP__)
{
set_errno(ERANGE);
number = infinite;
if (exponent < __FLT_MIN_EXP__)
{
number = divzero;
}
else
{
number = infinite;
}
goto errout;
}
/* Scale the result */
p10 = 10.0F;
n = exponent;
if (n < 0)
{