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
上输出它,然后解析它:
- 如果里面有一个
,指数在后面,前面是格式1.234中的尾数。。。即小数点前一位,只需根据指数移动小数点,在数字前面(负指数)或后面(正指数)添加所需数量的0e
- 如果内部没有
,则输出已经是固定格式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;
}