Ответ 1
Если использовать внешнюю библиотеку для достижения этой цели, вы можете пойти с fmtlib (эта библиотека, вероятно, превратится в стандарт), которая утверждает, что она быстрее, чем другие подходы (см. Их тесты).
#include <fmt/format.h>
std::string FloatToScientificString(float val, int width, int precision)
{
return fmt::format("{:>{}.{}e}", val, width, precision);
}
Это должно возвращать идентичную строку в качестве исходной функции, и вы не жертвуете безопасностью типа, как при подходах std::*printf
. При использовании abseil вместо этого (они утверждают, что они заметно быстрее, чем printf
-family здесь), функция выглядит так:
#include <absl/strings/str_format.h>
std::string FloatToScientificString(float val, int width, int precision)
{
return absl::StrFormat("%*.*e", width, precision, val);
}
Существует также форматированный формат, который не позволяет передавать спецификатор ширины или точности в качестве аргументов, но это работает одинаково хорошо:
#include <boost/format.hpp>
std::string FloatToScientificString(float val, int width, int precision)
{
const std::string fmt = "%" + std::to_string(width) + "." +
std::to_string(precision) + "e";
return boost::str(boost::format(fmt) % val);
}
и, наконец, без каких-либо внешних зависимостей, отличных от стандартной библиотеки (обратите внимание, что использование std::snprintf
превосходит std::sprintf
при проверке размера буфера, но ни одна из функций не является безопасной по типу):
#include <cstdio>
std::string FloatToScientificString(float val, int width, int precision)
{
static const int bufSize = 100;
static char buffer[bufSize];
std::snprintf(buffer, bufSize, "%*.*e", width, precision, val);
return std::string(buffer);
}
Правильный анализ эффективности этих параметров, вероятно, сам по себе. Любой из этих параметров должен быть заметно быстрее, чем исходный подход, используя std::stringstream
, хотя и все фрагменты, кроме std::snprintf
являются безопасными по типу.