提问人:rhodysurf 提问时间:1/16/2014 最后编辑:rhodysurf 更新时间:1/17/2014 访问量:2817
使用 C++ 打印带有一个前导零的指数表示法
Print exponential notation with one leading zero with C++
问:
我正在生成一个文本文件,用作 FORTRAN 输入文件。FORTRAN 程序指定它读取的值必须采用这样的格式
1.0
必须打印为
0.1000000E+01
截至目前,我最接近使用 iostream 的是
1.000000E+00
使用代码
cout << setprecision(6) << fixed << scientific << uppercase;
_set_output_format(_TWO_DIGIT_EXPONENT);
cout << 1.0 << endl;
有谁知道获得如上所示的前导零的最佳方法,最好使用 ostream 而不是 printf?
答:
1赞
chux - Reinstate Monica
1/16/2014
#1
C心想:
这不是一个很好的答案,因为首选C++答案。
char buf[20];
buf[0] = ' ';
double x = -1.234567;
sprintf(&buf[1], "% .6E", x*10);
if (buf[3] == '.') { // detect if x was INF or NAN
buf[0] = buf[1];
buf[1] = '0';
buf[3] = buf[2];
buf[2] = '.';
}
// Cope with leading potential space if needed
if (buf[0] == ' ') memmove(&buf[0], &buf[1], strlen(buf));
printf("%s\n", buf);
// -0.1234567E+00
弱点:如果小数点不是 '.' 或 INF 附近的 x,则会出现麻烦。
1赞
Stefano Sanfilippo
1/17/2014
#2
正如我所说,你问的是非标准的,但你可以通过一个技巧来实现:
#include <iostream>
#include <iomanip>
#include <cmath>
class Double {
public:
Double(double x): value(x) {}
const double value;
};
std::ostream & operator<< (std::ostream & stream, const Double & x) {
// So that the log does not scream
if (x.value == 0.) {
stream << 0.0;
return stream;
}
int exponent = floor(log10(std::abs(x.value)));
double base = x.value / pow(10, exponent);
// Transform here
base /= 10;
exponent += 1;
stream << base << 'E' << exponent; // Change the format as needed
return stream;
}
int main() {
// Use it like this
std::cout << std::setprecision(6) << std::fixed;
std::cout << Double(-2.203e-15) << std::endl;
return 0;
}
包装器是必需的,因为您无法重新定义 。Double
<<
double
我没有测试这种分离方式和浮点的几率,也许你可以想出一个更好的选择,但你明白了这个想法:)exponent
base
评论
0赞
chux - Reinstate Monica
1/17/2014
很好的C++答案。我过去曾尝试过这种方法来处理类似的问题,但在接近 10 的幂值时遇到了麻烦。像 0.9999999999e-10 或 1.00000000001-10 这样的值会得出 和 的不匹配对,尤其是零件。您可能想尝试此类测试用例。exponent
base
floor(log10...
0赞
rhodysurf
1/17/2014
我正在查看缓存的版本。出于某种原因,第一个 if 语句 where 告诉我没有运算符与这些操作数匹配x==0
0赞
Stefano Sanfilippo
1/17/2014
对不起,这是一个错别字,我在一分钟左右之前修复了它。立即尝试使用代码。
0赞
rhodysurf
1/17/2014
谢谢,它现在可以工作了。我有点生气自己没有抓住这个简单的错误。
0赞
chux - Reinstate Monica
1/17/2014
@Stefano 像 0.9999999999999 这样的值可以很好地分解:frexp10 或 frexp,但有限精度设置(此处为 6)会导致四舍五入并打印“1.000000”。 不知道这个小数点偏移,并打印其原始值。四舍五入实际上是一种数学运算,也应该影响 ,但不会,这在这种方法中留下了一个小漏洞。stream << base
exponent
base
exponent
0赞
n. m. could be an AI
1/17/2014
#3
- 创建一个不打印小数点的区域设置方面,并对其进行填充。
cout << "0." << setprecision(6) << fixed << scientific << uppercase << number * 10;
评论
0赞
rhodysurf
1/17/2014
这可行,但为打印的每个数字设置和重置 ios 标志似乎效率较低
0赞
chux - Reinstate Monica
1/17/2014
这会在“0”之后打印“-”号吗?
0赞
n. m. could be an AI
1/17/2014
我认为您可以打电话而不是<<,而不是一直重置所有内容。.write("0.", 2)
0赞
n. m. could be an AI
1/17/2014
@chux:是的,我的错误;)因此,您也需要手动打印,并在刻面中抑制它。-
评论
1.000000E+01
0.100000E+01
1.000000E+00
cout << 1 << endl;
1.000000E+01
1
cout << 1 << endl;
operator<<(int)
float
cout << 2.0 << endl;
2.000000E+00