我已经实现了atof函数。这是我的实现
double atof(const char *str)
{
double a; /* the a value in a*10^b */
double decplace; /* number to divide by if decimal point is seen */
double b; /* The b value (exponent) in a*10^b */
int sign = 1; /* stores the sign of a */
int bsign = 1; /* stores the sign of b */
while (*str && isspace(*str))
++str;
if (*str == '+')
++str;
if (*str == '-') {
sign = -1;
++str;
}
if ((*str == 'n' || *str == 'N') &&
(str[1] == 'a' || str[1] == 'A')
&& (str[2] == 'n' || str[2] == 'N'))
return NAN * sign;
if ((*str == 'i' || *str == 'I') && (str[1] == 'n' || str[1] == 'N') &&
(str[2] == 'f' || str[2] == 'F'))
return INFINITY * sign;
for (a = 0; *str && isdigit(*str); ++str)
a = a * 10 + (*str - '0');
if (*str == '.')
++str;
for (decplace = 1.; *str && isdigit(*str); ++str, decplace *= 10.)
a = a * 10. + (*str - '0');
if (*str == 'e' || *str == 'E') {
/* if the user types a string starting from e, make the base be 1 */
if (a == 0)
a = 1;
++str;
if (*str == '-') {
bsign = -1;
++str;
}
if (*str == '+')
++str;
for (b = 0; *str && isdigit(*str); ++str)
b = b * 10 + (*str - '0');
b *= bsign;
}
else
b = 0;
return (a * sign / decplace) * pow(10, b);
}发布于 2016-02-14 20:28:25
如果我转换"0e+1",我将返回1,因为这些行:
/\* if the user types a string starting from e, make the base be 1 \*/ if (a == 0) a = 1;
该检查不能仅仅是a == 0,因为'e'之前的部分可能是0,在我的示例中。解决这一问题的一种方法是在解析任何数字之前检查字符串是否以'e'开头,如果是这样,则将a设置为1。
大多数情况下,您不会解析任何e+exponent部件,但目前无论如何都要调用pow(),这使得您的函数比它可能的速度慢:
返回(a *标志/标记)* pow(10,b);
您应该避免调用pow(),除非您需要它。这里有一种方法(不一定是最好的方法):
return (a * sign / decplace) * ((b == 0) ? 1 : pow(10, b));编辑:一个用户质疑pow()优化是否有用。对于避免调用"55.5"的版本,我在输入pow()上运行了100000000次原始函数。结果:
Original version: 2.55 sec
Modified version: 1.10 sec我还对代码进行了不同的修改,以避免对1进行额外的乘法,如下所示:
if (*str == 'e' || *str == 'E') {
// (All the same code here)
b *= bsign;
return (a * sign / decplace) * pow(10, b);
}
return a * sign / decplace;这个更快:
Second modified version: 1.00 sec发布于 2016-02-15 02:30:37
实现精确的atof函数是令人惊讶的困难,因为没有限制的数字,代码可能需要读取,以确保正确的四舍五入。例如,考虑以下两个值:
第一轮应为12012345.0f;第二轮应为12012346.0f。函数不需要对输入字符串执行广泛的计算;只要观察到某个点上是否有任何非零位数就足够了,但是处理所有这些情况的逻辑是很棘手的。
发布于 2016-02-18 03:17:40
DBL_MAX附近。使用像"0.0001e310"这样的输入返回inf而不是1.00000e+307。返回(a *标志/标记)* pow(10,b);DBL_MIN附近丢失精度,在DBL_TRUE_MIN附近丢失总精度。decplace是10的幂,只需使用整数值并将其添加到b。这将大大减少但不会消除DBL_MAX, DBL_MIN,DBL_TRUE_MIN附近的问题。精度损失较小,但不完全消除。IOWs,生成的double将更接近最好的。编辑->还有一个简单的改进:不要使用... * pow(10, b),而是使用(* ... * pow(5, b)) * pow(2,b)。这将允许精确的计算接近于double的极值,而不撤消超过/在流下。atof()的一部分是测试它的正确性。通过将其重命名为my_atof()并根据标准atof()进行测试将是第一步。然后评估这两个函数的紧密程度。这篇文章漏掉了任何统计数据,所以我想没有做过任何统计。对于任何数学函数,都应该尝试这样的分析,甚至是粗糙的分析。注意,这样的测试代码可能比这个atof()要多得多,而且它是工作的。如果确实对改进算法感兴趣,那么首先编写一个好的atofloat() (只使用float数学),然后将其与strtod()进行比较。NAN上使用sign的明确共识,所以可能需要也可能不需要使用return NAN * sign;。而且,该代码可能不会在-NAN中提供结果。考虑使用copysign()。一个FP角落的案子。isspace()期望在unsigned char (或EOF)中有一个值。对于有符号的char,下面是一个负值问题。// while (*str && isspace (*str )) // fix with cast或其他方法while (*str && isspace((无符号字符) *str))https://codereview.stackexchange.com/questions/119986
复制相似问题