转换字符串到浮点数,c++实现
visual studio - Convert string to float, C++ implementation
VS最小双值= 2.2250738585072014e-308。Atof函数将字符串转换为双精度值,例如当您在调试器中查看此值时,您将获得原始字符串表示。
double d = atof("2.2250738585072014e-308"); // debugger will show 2.2250738585072014e-308
正如我们所看到的,double值不是反规范化的(没有DEN)
我尝试在将string转换为double时实现相同的精度。下面是代码:
double my_atof(char* digits, int digits_length, int ep)
{
int idot = digits_length;
for (int i = 0; i < digits_length; i++)
{
if (digits[i] == '.')
{
idot = i;
break;
}
}
double accum = 0.0;
int power = ep + idot - 1;
for (int i = 0; i < digits_length; i++)
{
if (digits[i] != '.')
{
if (digits[i] != '0')
{
double base_in_power = 1.0;
if (power >= 0)
{
for (int k = 0; k < power; k++) base_in_power *= 10.0;
}
else if (power < 0)
{
for (int k = 0; k < -power; k++) base_in_power *= 0.1;
}
accum += (digits[i] - '0') * base_in_power;
}
power--;
}
else power = ep - 1;
}
return accum;
}
现在,让我们试试:
char* float_str = "2.2250738585072014";
int float_length = strlen(float_str);
double d = my_atof(float_str, float_length, -308);
调试显示d = 2.2250738585072379e-308。我试着替换
for (int k = 0; k < -power; k++) base_in_power *= 0.1;
for (int k = 0; k < -power; k++) base_in_power /= 10.0;
,但它会导致非规范化的值。如何实现与VS相同的精度,使调试器将显示相同的数字?
问题是0.1
常数的双表示,或者除以10.0
,产生完全相同的结果:10的负幂在浮点数中没有精确的表示,因为它们没有精确的表示为2的负幂的和。
当你通过重复乘法计算10的负幂时,你会累积误差。开始的几个负幂是正确的,但在0.000001
之后,差异变得明显。运行这个程序看看发生了什么:
double p10[] = {
0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001, 0.0000000001
};
int main(void) {
double a = 1;
for (int i = 0 ; i != 10 ; i++) {
double aa = a * 0.1;
double d = aa - p10[i];
printf("%d %.30lfn", aa == p10[i], d);
a = aa;
}
return 0;
}
输出如下所示:
1 0.000000000000000000000000000000
1 0.000000000000000000000000000000
1 0.000000000000000000000000000000
1 0.000000000000000000000000000000
1 0.000000000000000000000000000000
0 0.000000000000000000000211758237
0 0.000000000000000000000026469780
0 0.000000000000000000000001654361
0 0.000000000000000000000000206795
0 0.000000000000000000000000025849
演示。
前几个幂完全匹配,但随后出现了一些差异。在字符串到浮点数的转换过程中,如果使用计算的幂来组合数字,则累积的错误会进入最终结果。如果库函数使用了一个查找表(参见这个示例实现),那么您得到的结果将与它们得到的结果不同。
你可以通过硬编码一个10的负幂表来修复你的实现,并引用这个表而不是手动计算幂。或者,您可以通过连续乘法构造一个正的十幂,然后做一个单除法1 / pow10
来构造相应的负幂(演示)。
相关文章:
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- std::random_device是如何实现的