我一直在研究一些代码,它们有一个奇怪的优化错误,在这个过程中,我偶然发现了strtod()
中的错误条件,它的行为与strtof()
不同,恰好处于非正规值的边缘.strtof()
的行为在我看来完全合理,但strtod()
并非如此!具体地说,对于输入值"-0x1.fffffffffffffp-1023"
,它返回-0.0
.
这是在其正确解码的表示"-0x1.ffffffffffffep-1023"
中设置为1的额外比特.更奇怪的是,添加额外的尾随数字得到的值是2-1018,我无法解释.在我看来,从非正规到正常浮点转换的特殊边缘情况被错误地处理,导致零值.
有没有人能解释额外数字引起的另一个奇怪的数字?
MSC 2022和Intel 2023上的故障相同
Double&;输出的示例代码MRE(浮点数的工作方式与预期不谋而合)
// strtod() fails to handle edge case overflow from denormals correctly
//
// Problem manifests on both MS 2022 and Intel 2023 compilers so by design? but why???
//
// using Windows 11 and Microsoft Visual Studio Community 2022 (64-bit) - Version 17.1.0
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
void Show(const char *name, int err, double arg)
{
unsigned iarg[2];
memcpy(&iarg, &arg, sizeof arg);
printf("\n\"%25s\" decoded errno=%i as 0x%08x%08x %.13a %30.22g",
name, err, iarg[1], iarg[0], arg, arg);
}
void DecodeShow(const char *value)
{
char *stopstr;
double arg;
errno = 0;
arg = strtod(value, &stopstr);
Show(value, errno, arg);
}
int main(void)
{
printf("Test of doubles near denorm boundary\n");
DecodeShow("-0x1.ffffffffffffp-1023");
DecodeShow("-0x1.ffffffffffffep-1023");
DecodeShow("-0x1.ffffffffffffe8p-1023");
DecodeShow("-0x1.fffffffffffff0p-1023"); // hard fail == -0.0 !
DecodeShow("-0x1.fffffffffffff8p-1023");
DecodeShow("-0x1.ffffffffffffffp-1023");
DecodeShow("-0x1.fffffffffffffffp-1023");
printf("\n");
DecodeShow("0x1.ffffffffffffe8p-1023");
DecodeShow("0x1.fffffffffffff0p-1023"); // hard fail == +0.0
DecodeShow("0x1.fffffffffffff8p-1023");
DecodeShow("0x1.ffffffffffffffp-1023");
printf("\n");
DecodeShow("0x1.ffffffffffffep-1022");
DecodeShow("-0x1.fffffffffffffp-1022");
DecodeShow("-0x1.fffffffffffff8p-1022");
DecodeShow("-0x1.ffffffffffffffp-1022");
}
故障边界附近的选定输出:
" -0x1.ffffffffffffep-1023" decoded errno=0 as 0x800fffffffffffff -0x0.fffffffffffffp-1022 -2.225073858507200889025e-308
"-0x1.ffffffffffffe8p-1023" decoded errno=0 as 0x800fffffffffffff -0x0.fffffffffffffp-1022 -2.225073858507200889025e-308
"-0x1.fffffffffffff0p-1023" decoded errno=0 as 0x8000000000000000 -0x0.0000000000000p+0 -0
"-0x1.fffffffffffff8p-1023" decoded errno=0 as 0x8040000000000000 -0x1.0000000000000p-1019 -1.780059086805761106472e-30
我认为,超出机器精度的额外尾随数字不应该从根本上改变strtod
这样解码的浮点值.我不能通过使用十进制数字输入字符串来引发同样的失败-跨越边界的转换似乎表现良好(尽管我不能排除我还没有发现的一个Spot值不起作用).