how to prevent numbers from showing up in scientific notations

半城伤御伤魂 提交于 2019-12-28 21:41:28

问题


We have a StreamBuffer class in which we haven't implemented std::fixed operations and I am trying to prevent number showing up in scientific notations. With my below code some numbers are getting shown in scientific notations. We want to avoid doing any allocations so that's why we implemented StreamBuffer class because of performance reason.

Below is the code:

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 << "}";
        }
    }
}

And this is the way it is being called:

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);
}

I tried using like as shown below and I got an error by which I understood we cannot use std::fixed on my StreamBuffer class.

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

What is the alternative to std::fixed I can use here which doesn't do any allocations at all. I was thinking of converting number to string and then apply std::fixed on it but that will do some allocations as well which I want to avoid that.

What is the best way to do this which is performance efficient and doesn't do any allocations? I have a below solution but it will do some allocations as it uses string. I can call below method from my above code.

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

Is there any other optimized and efficient way?


回答1:


StreamBuffer class must inherit from std::ios_base (or some of it's derivatives such as std::ostream) for your expected behaviour. std::fixed can only work with derivative implementations of what is available as part of the STL.

Additionally, if you have access to an std::ios_base, you can also play around with std::ios_base::precision.

If you are stuck in a situation where you cannot update the class then the most commonly used and traditional way is by way of scaling floats. In the interest of reducing duplication please have a look at the already answered question here. For example, for a 3rd degree of precision, I'd replace all 'value' instances with:

// 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

Having better understood the questioner's requirements. I have realised that the above would not work with exponents. In order to get around this I propose doing the following:

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

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

This, however, will most certainly allocate more memory.





回答2:


Just use 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:


It looks to me like maybe you should try CppFormat. There are some examples of how to use it for formatting here.



来源:https://stackoverflow.com/questions/35258164/how-to-prevent-numbers-from-showing-up-in-scientific-notations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!