提问人:MusicMaster 提问时间:4/16/2023 最后编辑:MusicMaster 更新时间:4/18/2023 访问量:222
C++17 std::to_chars 和 std::from_chars 可移植性
C++17 std::to_chars and std::from_chars portability
问:
根据 cppreference,“仅当两个函数来自同一实现时,才能保证 std::to_chars/std::from_chars 可以完全恢复由 std::from_chars/std::to_chars 格式化的每个浮点值。
如果其中一个在不同的实现上运行,这可能会导致什么样的麻烦? 浮点数的哪些值(十进制和十六进制)会引起麻烦? 他们俩至少可以被信任,好吧,说“大多数”价值观,或者这只是一个不信任的不行吗?
[ 后续编辑: ]我坚持使用和.处理
所需的强制到/从“C”语言环境恢复,我使用了
每个线程等,不触及全局区域设置。
尽管有 1000 次操作,但速度似乎足够快,尽管没有正式测试。
我想知道区域设置调用是否是一个很大的速度?
我还了解到“0x”在 to/from_chars 中是被禁止的。我需要那个。strtod
snprintf
uselocale
答:
这是个好问题。可移植到后续编译器版本以及系统之间的数据交换需要一致性。因此,我编写了这个快速程序来生成 100,000 个随机的 32 位值。转换为浮点数,然后运行它们,然后运行它们。我从生成的所有字符中生成了一个 CRC16 值。如果这些在编译器或未来的编译器之间匹配,那么可以预期数据很可能是可移植的。此外,还测试了 to/from 转换会产生相同的浮点数,尽管这是标准中的要求。std::to_chars
std::from_chars
以下代码在 MSVC、CLang 和 GCC 中生成 crc=931c
#include <random>
#include <charconv>
#include <string>
#include <bit>
#include <iostream>
//#define CRC16
//#include "crc.h"
struct CRC16 {
uint16_t state{ 0xffff };
static constexpr uint16_t poly = 0x1021;
uint16_t clk(char c)
{
state ^= c & 255;
for (int i = 0; i < 8; i++)
{
if (state & 0x8000)
state = (state << 1) ^ poly;
else
state = (state << 1);
}
return state;
}
};
int main()
{
CRC16 crc;
constexpr uint32_t mask{ 0x7f800000 };
std::mt19937 g(1);
std::uniform_int_distribution<uint32_t> dist;
// run 100,000 random bit float patterns and test for conversion consistency
for (int i = 0; i < 100000; i++)
{
char result[100]{};
uint32_t x = dist(g);
// do not test NaN or De-normalized floats
if (((x & mask) != mask) && (x & mask) != 0)
{
float f = std::bit_cast<float>(x);
float fret;
auto res1 = std::to_chars(&result[0], &result[100], f);
for (char* p = &result[0]; p < res1.ptr; p++)
crc.clk(*p);
auto res2 = std::from_chars(&result[0], res1.ptr, fret);
if (f != fret)
throw "oops: mismatch";
}
}
std::cout << std::hex << crc.state << '\n';
}
请注意,这仅测试浮点数。微小的修改也会测试双打。此外,如果这很关键,测试完整的浮点数集是可行的,但需要一段时间才能运行。Doubles 无法测试整个状态空间。
评论