C++、科学计数法、格式数字

问题描述 投票:0回答:5

是否可以通过以下方式以科学记数法格式化字符串:

  • 在指数中设置固定位置:1

  • 设置尾数固定小数位:0

     double number = 123456.789
    

所以数字应该格式化

  1e+5

我无法为尾数设置 0 小数点:

cout.precision(0);
cout << scientific << number;

结果:

1.234568e+005
c++ format scientific-notation
5个回答
8
投票

我不知道如何在指数字段中获取单个数字,但以下内容符合您的所有其他要求。

#include <iostream>
#include <iomanip>

int main()
{
  const double number = 123456.789;

  std::cout << std::setprecision(0) << std::scientific << number << std::endl;
}

输出:

1e+05

编辑:
快速搜索了标准(N3291),但找不到任何有关使用科学记数法时指数字段中的位数的内容。这可能是实现定义的。


6
投票

您可以使用 C++20 来完成

std::format
:

double number = 123456.789;
auto s = std::format("{:.0e}\n", number); // s == "1e+05"
s.erase(s.size() - 2, 1); // s == "1e+5"

std::format
广泛使用之前,您可以使用 {fmt} 库
std::format
基于:

#include <fmt/core.h>
    
double number = 123456.789;
auto s = fmt::format("{:.0e}\n", number); // s == "1e+05"
s.erase(s.size() - 2, 1); // s == "1e+5"

免责声明:我是 {fmt} 和 C++20 的作者

std::format


3
投票

我不确定您使用的 C++ 编译器会为您提供 3 位指数 - C 和 C++ 标准要求至少 2 位数字,而这正是 g++ 所做的。使用标准 C 或 C++ I/O 函数无法仅获取一位数字,因此您必须推出自己的解决方案。由于进行浮点到字符串的转换是一个非常棘手的问题[PDF],我强烈建议不要这样做,而是对结果进行后处理。

这是一种方法:

// C version; you can rewrite this to use std::string in C++ if you want
void my_print_scientific(char *dest, size_t size, double value)
{
    // First print out using scientific notation with 0 mantissa digits
    snprintf(dest, size, "%.0e", value);

    // Find the exponent and skip the "e" and the sign
    char *exponent = strchr(dest, 'e') + 2;

    // If we have an exponent starting with 0, drop it
    if(exponent != NULL && exponent[0] == '0')
    {
        exponent[0] = exponent[1];
        exponent[1] = '\0';
    }
}

2
投票

一旦有了字符串,你实际上可以格式化任何东西。更多的 C++ 代码如下所示:

const double number = 123456.789;
const int expSize = 1;
std::ostringstream oss;
std::string output;
oss << std::scientific << number;
unsigned int ePos = oss.str().find("e");
unsigned int dPos = oss.str().find(".");
if(ePos == 0){
    //no exponent
}
else if(dPos == 0){
    //not decimal
}
else{
    output = oss.str().substr(0, dPos) + oss.str().substr(ePos, 2);
    if(oss.str().size()-expSize > ePos+1)
        output += oss.str().substr(oss.str().size()-expSize, oss.str().size());
    else{
        //expSize too big (or bug -> e used but no exponent?)
    }
    std::cout << output;
}

输出:

1e+5

您可以在 expSize 中设置指数大小,这适用于任意大指数。

希望有帮助!


1
投票

这是一个流解决方案:

#include <iostream>
#include <iomanip>
using namespace std;

template<typename T>
struct scientificNumberType
{
    explicit scientificNumberType(T number, int decimalPlaces) : number(number), decimalPlaces(decimalPlaces) {}

    T number;
    int decimalPlaces;
};

template<typename T>
scientificNumberType<T> scientificNumber(T t, int decimalPlaces)
{
    return scientificNumberType<T>(t, decimalPlaces);
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const scientificNumberType<T>& n)
{
    double numberDouble = n.number;

    int eToThe = 0;
    for(; numberDouble > 9; ++eToThe)
    {
        numberDouble /= 10;
    }

    // memorize old state
    std::ios oldState(nullptr);
    oldState.copyfmt(os);

    os << std::fixed << std::setprecision(n.decimalPlaces) << numberDouble << "e" << eToThe;

    // restore state
    os.copyfmt(oldState);

    return os;
}

使用示例:

int main()
{
    double e = 1.234;

    cout << scientificNumber(e, 1) << " " << scientificNumber(e, 3);

    return 0;
}

输出:

1.2e0 1.234e0

© www.soinside.com 2019 - 2024. All rights reserved.