C++ 如何将十进制科学符号float/double转换为普通字符串

C++ 如何将十进制科学符号float/double转换为普通字符串,c++,floating-point,scientific-notation,C++,Floating Point,Scientific Notation,我知道当数字不是很大时,有很多问题可以解决这个问题,但当数字很大时(仍在浮点/双精度范围内),输出将失去精度: #include <stdio.h> #include <iostream> #include <sstream> int main() { double d = -1e307, d2 = 1e307; std::cout << std::fixed << d << std::endl;

我知道当数字不是很大时,有很多问题可以解决这个问题,但当数字很大时(仍在浮点/双精度范围内),输出将失去精度:

#include <stdio.h>
#include <iostream>
#include <sstream>

int main() {
    double d = -1e307, d2 = 1e307;
    std::cout << std::fixed << d << std::endl;

    printf("d2 is %lf\n", d2);
    return 0;
}

但这显然是不对的!如何进行真正的转换

问题在于,双精度浮点数用64位二进制格式表示,其精度约为16位十进制数字。因此,您看到的整数值是以IEE-754格式表示的最接近
1e307
(分别为
-1e307
)的整数

如果您知道您需要另一个表示,那么您必须亲自构建它。最简单的方法(IMHO)是以默认格式在
stringstream
上输出它,然后解析它:

  • 如果里面有一个
    e
    ,指数在后面,前面是格式1.234中的尾数。。。即小数点前一位,只需根据指数移动小数点,在数字前面(负指数)或后面(正指数)添加所需数量的0
  • 如果内部没有
    e
    ,则输出已经是固定格式

或者,您可以尝试找到一个大的十进制库,该库在内部使用十进制数的精确表示法(如果您没有发现任何符合您的要求,也可以编写自己的库)。

实际上我自己处理过这个问题,这是我的代码,该函数将任意浮点字符串转换为普通字符串

此功能的灵感来源于

//DW:删除e
std::string trim_real(std::string str){
//DW:全部为小写
std::transform(str.begin()、str.end()、str.begin()、::tolower);
//DW:查找“e”和“.”
尺寸=str.find_first_of(“e”);
std::string se=str.substr(pe+1,str.size()-(pe+1));
int de=std::stoi(se);
//DW:获取不带“e”的字符串
std::string sc=str.substr(0,pe);

std::cout浮点数不精确。除了不使用浮点数之外,没有其他解决方法。
std::cout数字没有格式。格式仅在尝试从数字生成字符串时适用。如果得到意外结果,那是因为数字不能准确地表示为浮点数,您应该创建你自己的类来存储十进制科学记数法来存档这个。“这显然是不正确的!”:与您的想法相反,这是非常正确的,因为它与双精度浮点提供的精度兼容。整数1e307的精确表示至少需要1020位数字,而本机不支持这些数字(它们在日常应用中几乎没有用处)。谢谢您的回答,在深入谷歌搜索后,我找到了一个解决方案并对其进行了改进,您可以在下面查看我的改进解决方案和原始解决方案:-)
-9999999999999999860310597602564577717002641838126363875249660735883565852672743849064846414228960666786379280392654615393353172850252103336275952370615397010730691664689375178569039851073146339641623266071126720011020169553304018596457812688561947201171488461172921822139066929851282122002676667750021070848.000000

d2 is 9999999999999999860310597602564577717002641838126363875249660735883565852672743849064846414228960666786379280392654615393353172850252103336275952370615397010730691664689375178569039851073146339641623266071126720011020169553304018596457812688561947201171488461172921822139066929851282122002676667750021070848.000000
// DW: remove e
std::string trim_real(std::string str) {
    // DW: all to lowercase
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);

    // DW: find "e" and "."
    size_t pe = str.find_first_of("e");
    std::string se = str.substr(pe + 1, str.size() - (pe + 1));
    int de = std::stoi(se);

    // DW: get string without "e"
    std::string sc = str.substr(0, pe);
    std::cout << "sc is " << sc << std::endl;

    // DW: remove uneccessary 0
    size_t pf0 = sc.find_first_not_of("0");
    size_t pl0 = sc.find_last_not_of("0");
    std::string sc_trim = sc.substr(pf0, pl0 - pf0 + 1);
    std::cout << "sc_trim is " << sc_trim << std::endl;

    // DW: move "." according to e
    size_t pp = sc_trim.find_first_of(".");
    if (pp == std::string::npos) {
        // DW: this means there is no "."
        pp = 0;
    }
    int pp_tobe = pp + de;

    sc_trim.erase(pp, 1);
    if (de > 0) {
        // DW: should move "." to the right
        if (pp_tobe < sc_trim.size()) {
            sc_trim.insert(pp_tobe, ".");
        } else {
            sc_trim += std::string(pp_tobe - sc_trim.size() + 1, '0');
            sc_trim += ".0";
        }
    } else {
        // DW: should move "." to the left
        if (pp_tobe >= 0) {
            sc_trim.insert(pp_tobe, ".");
        } else {
            sc_trim = "." + std::string(0 - pp_tobe, '0') + sc_trim;
        }
    }

    if (sc_trim == ".") {
        // DW: this means sc_trim is actually 0 now
        sc_trim = "0.0";
    }
    return sc_trim;
}