Подтвердить что ты не робот

Как предотвратить появление чисел в научных обозначениях

У нас есть класс StreamBuffer, в котором мы не реализовали операции std::fixed, и я пытаюсь предотвратить число, отображаемое в научных обозначениях. С моим приведенным ниже кодом некоторые цифры отображаются в научных обозначениях. Мы хотим избежать каких-либо распределений, поэтому мы внедрили класс StreamBuffer из-за причин производительности.

Ниже приведен код:

T value = 0;

template<typename U> void process(U& buf, DataOption holder) const {
    if (holder == DataOption::TYPES) {
        switch (type_) {
        case teck::PROC_FLOAT:
            buf << "{\"float\":" << value << "}";
            break;
        case teck::PROC_DOUBLE:
            buf << "{\"double\":" << value << "}";
            break;
        default:
            buf << "{\"" << type_ << "\":" << value << "}";
        }
    }
}

И так он называется:

void HolderProcess::dump(std::ostream& os, DataOption holder) const 
{
    process<std::ostream>(os, holder);
}

void HolderProcess::dump(StreamBuffer& buffer, DataOption holder) const
{
    process<StreamBuffer>(buffer, holder);
}

Я попытался использовать, как показано ниже, и получил ошибку, по которой я понял, что мы не можем использовать std::fixed в моем классе StreamBuffer.

case teck::PROC_DOUBLE:
    buf << "{\"double\":" << std::fixed << value << "}";

Какова альтернатива std::fixed, которую я могу использовать здесь, которая вообще не выполняет никаких распределений. Я думал о преобразовании числа в строку, а затем применяю к нему std::fixed, но это также сделает некоторые выделения, которые я хочу избежать.

Каков наилучший способ сделать это, эффективность которого эффективна и не делает каких-либо ассигнований? У меня есть решение ниже, но оно будет делать некоторые выделения, так как использует строку. Я могу вызвать метод ниже из моего кода.

template <typename T> string str(T number)
   {
       std::ostringstream ss;
       ss << std::fixed << number;
       return ss.str();
   }

Есть ли какой-либо другой оптимизированный и эффективный способ?

4b9b3361

Ответ 1

Класс StreamBuffer должен наследовать от std:: ios_base (или некоторых его производных, таких как std:: ostream) для вашего ожидаемого поведения. std:: fixed может работать только с производными реализациями того, что доступно как часть STL.

Кроме того, если у вас есть доступ к std:: ios_base, вы также можете играть с std:: ios_base:: precision.

Если вы застряли в ситуации, когда вы не можете обновить класс, наиболее распространенным и традиционным способом является масштабирование поплавков. В целях сокращения дублирования, пожалуйста, ознакомьтесь с уже ответившим вопросом здесь. Например, для третьей степени точности я заменил бы все экземпляры "значение":

// case teck::PROC_FLOAT:
static_cast<float>( static_cast<int>(value*1000) ) / 1000
// case techk::PROC_DOUBLE:
static_cast<double>( static_cast<long long>(value*1000) ) / 1000

Лучше поняли требования допрашивающего. Я понял, что вышеупомянутое не будет работать с экспонентами. Чтобы обойти это, я предлагаю сделать следующее:

case teck::PROC_FLOAT:
        std::stringstream ss;

        ss << std::fixed << value;
        buf << "{\"float\":" << ss.str() << "}";
        break;

Это, однако, будет, безусловно, выделять больше памяти.


Ответ 2

Просто используйте snprintf:

#include <cstdio>
#include <limits>
#include <iostream>

int main() {
    double value = 0.1234567890123456789;
    const int Precision = std::numeric_limits<double>::digits10;
    const std::size_t StringBufferSize = Precision + 3; // sign, dot and terminating zero.
    char str[StringBufferSize];
    std::snprintf(str, StringBufferSize - 1, "%.*f", Precision, value);
    str[StringBufferSize - 1] = 0;
    // buf << "{\"double\":" << str << "}";
    std::cout << str << '\n';
}

Ответ 3

Мне кажется, что, возможно, вам стоит попробовать CppFormat. Есть несколько примеров того, как использовать его для форматирования здесь.