是静止的,是完全确定的

Is stof, strtof deterministic?

本文关键字:静止      更新时间:2023-10-16

我正在从字符串中读取浮点数。它们可以写成各种形式,因此

float f1 = strtof("999999999999.16");
float f2 = stof("000999999999999.1600000");
assert(f1 == f2);

我可以确定断言总是为真,无论前导零和后置零如何?分隔符总是一个点,stof不处理逗号。

C11标准,在7.22.1.3p9中,对C的strtof/strtod/strtold(这应该是c++版本下面使用的,至少从cppreference判断)有这样的说法:

如果主题序列具有十进制形式并且最多DECIMAL_DIG位有效数字(在<float.h>中定义),则结果应正确舍入。

假设你的两行代码有相同的有效位数,它们应该表现相同。但这仅仅是一种猜测,因为标准在这里根本就没有提到"有效数字";在其他任何地方都没有提到它,并且标准没有更明确地说明前导(小数点之前)或尾随(小数点之后)零。

c++ 14(§21.5)标准规定:

float stof(const string& str, size_t* idx = 0);

double stod(const string& str, size_t* idx = 0);

long double stold(const string& str, size_t* idx = 0);

效果:前两个函数调用strtod(str.c_str(), ptr),第三个函数调用strtold( str.c_str(), ptr)。每个函数返回转换后的结果(如果有的话)。参数ptr指定了一个指向函数内部对象的指针,该对象用于确定在*idx中存储的内容。如果该函数没有抛出异常且idx != 0,则该函数在*idx中存储str的第一个未转换元素的索引。

因此,在许多情况下,它们将是相同的,但是中间的double确实打开了双舍入的可能性。例如,如果str = "1.0000000596046448",那么最接近的float(假设IEEE754算法)是1.0000001f,而最接近的double正好在1.0f1.0000001f之间,因此随后转换到float将四舍五入到1.0f

至少理论上是这样的。但是,在实践中,我无法重新创建:http://ideone.com/NMRy14