如何设置std::scientific的格式
How to set format of std::scientific
我想将 12345.0 打印为 0.1235e+05。但是下面的代码给出了 1.23450e+04。有没有办法控制 std::scientific?
的格式
#include <iostream>
#include <string>
#include <sstream>
int main()
{
double a = 12345.0;
std::stringstream s;
s.precision(3);
s << std::scientific;
s << a;
std::cout << s.str() << std::endl;
return 0;
}
输出为
1.235e+04
我也试过这里的代码Print exponential notation with one leading zero with C++但是四舍五入有问题。如果我将精度设置为 4,它不会四舍五入并给出 0.1234E5,但它应该是 0.1235E5。
有什么解决办法吗?
那不是科学形式。科学形式必须产生 1-10 之间的数字并乘以 10
的幂
资料来源:http://chemed.chem.purdue.edu/genchem/topicreview/bp/ch1/scinot.html
我通过添加两行代码更正了link Print exponential notation with one leading zero with C++中给出的解决方案中的错误。我还重复了正确格式的过程:
int p = stream.precision();
base = round(base * pow(10, p)) / pow(10, p);
它现在进行了正确的舍入并给出了 0.1235E5。这是完整的代码:
#include <iostream>
#include <string>
#include <sstream>
#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.0;
int p = stream.precision(); // This line is added to correct the code
base = round(base * pow(10, p)) / pow(10, p); // This line is added to correct the code
exponent += 1;
double x2 = base * pow(10, exponent);
exponent = floor(log10(std::abs(x2)));
base = x2 / pow(10, exponent);
// Transform here
base /= 10.0;
base = round(base * pow(10, p)) / pow(10, p); // This line is added to correct the code
exponent += 1;
stream << base << "+e" << exponent;
return stream;
}
int main()
{
//double a = 12345.0;
double a = 99995.01;
std::stringstream s;
s.precision(4);
s << Double(a);
std::cout << s.str() << std::endl;
return 0;
}
重新发明 double
到字符串转换的一个问题是许多极端情况。
考虑将 99995.0 附近的值打印到 4 个位置
void foo(double value, int precision) {
if (value == 0.) {
printf("%g\n", 0.0);
}
int exponent = (int) floor(log10(fabs(value)));
double base = value / pow(10, exponent);
base /= 10.0;
int p = precision;
base = round(base * pow(10, p)) / pow(10, p);
exponent++;
printf("%.*fE%d\n", p, base, exponent);
bar(value, precision);
}
foo(99994.99, 4);
foo(99995.01, 4);
版画
0.9999E5
1.0000E5
而不是希望
0.9999E5
0.1000E6
与其尝试计算浮点到字符串的库转换,不如简单地post将字符串处理为所需的格式。
下面是C,但是OP正在寻找C++,所以以此为指导。
void bar(double value, int precision) {
precision--;
char buf[400];
snprintf(buf, sizeof buf, "%.*e", precision, value);
if (isfinite(value)) {
char *e = strchr(buf, 'e');
char *first_digit = e - precision - 2;
int expo = atoi(e + 1) + 1;
printf("%.*s0.%c%.*sE%d\n", !isdigit((unsigned char )buf[0]), buf,
*first_digit, precision, first_digit + 2, expo);
} else {
printf("%s\n", buf);
}
}
bar(99994.99, 4);
bar(99995.01, 4);
版画
0.9999E5
0.1000E6
“如果我将精度设置为 4,它不会舍入并给出 0.1234E5,但它应该是 0.1235E5。”
这是因为默认舍入模式是“舍入到最近,并列到偶数”,而 OP 希望“舍入到最近,并列到远”。
base = round(base * pow(10, p)) / pow(10, p);
等代码可能会在 select 情况下实现 OP 的目标,因为此处的乘法和除法可能会由于不精确而导致舍入,有时会在所需的方向上舍入。这在所有 double
中都不可靠,无法实现“舍入到最近,关系到远”。
我想将 12345.0 打印为 0.1235e+05。但是下面的代码给出了 1.23450e+04。有没有办法控制 std::scientific?
的格式#include <iostream>
#include <string>
#include <sstream>
int main()
{
double a = 12345.0;
std::stringstream s;
s.precision(3);
s << std::scientific;
s << a;
std::cout << s.str() << std::endl;
return 0;
}
输出为
1.235e+04
我也试过这里的代码Print exponential notation with one leading zero with C++但是四舍五入有问题。如果我将精度设置为 4,它不会四舍五入并给出 0.1234E5,但它应该是 0.1235E5。
有什么解决办法吗?
那不是科学形式。科学形式必须产生 1-10 之间的数字并乘以 10
的幂
资料来源:http://chemed.chem.purdue.edu/genchem/topicreview/bp/ch1/scinot.html
我通过添加两行代码更正了link Print exponential notation with one leading zero with C++中给出的解决方案中的错误。我还重复了正确格式的过程:
int p = stream.precision();
base = round(base * pow(10, p)) / pow(10, p);
它现在进行了正确的舍入并给出了 0.1235E5。这是完整的代码:
#include <iostream>
#include <string>
#include <sstream>
#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.0;
int p = stream.precision(); // This line is added to correct the code
base = round(base * pow(10, p)) / pow(10, p); // This line is added to correct the code
exponent += 1;
double x2 = base * pow(10, exponent);
exponent = floor(log10(std::abs(x2)));
base = x2 / pow(10, exponent);
// Transform here
base /= 10.0;
base = round(base * pow(10, p)) / pow(10, p); // This line is added to correct the code
exponent += 1;
stream << base << "+e" << exponent;
return stream;
}
int main()
{
//double a = 12345.0;
double a = 99995.01;
std::stringstream s;
s.precision(4);
s << Double(a);
std::cout << s.str() << std::endl;
return 0;
}
重新发明 double
到字符串转换的一个问题是许多极端情况。
考虑将 99995.0 附近的值打印到 4 个位置
void foo(double value, int precision) {
if (value == 0.) {
printf("%g\n", 0.0);
}
int exponent = (int) floor(log10(fabs(value)));
double base = value / pow(10, exponent);
base /= 10.0;
int p = precision;
base = round(base * pow(10, p)) / pow(10, p);
exponent++;
printf("%.*fE%d\n", p, base, exponent);
bar(value, precision);
}
foo(99994.99, 4);
foo(99995.01, 4);
版画
0.9999E5
1.0000E5
而不是希望
0.9999E5
0.1000E6
与其尝试计算浮点到字符串的库转换,不如简单地post将字符串处理为所需的格式。
下面是C,但是OP正在寻找C++,所以以此为指导。
void bar(double value, int precision) {
precision--;
char buf[400];
snprintf(buf, sizeof buf, "%.*e", precision, value);
if (isfinite(value)) {
char *e = strchr(buf, 'e');
char *first_digit = e - precision - 2;
int expo = atoi(e + 1) + 1;
printf("%.*s0.%c%.*sE%d\n", !isdigit((unsigned char )buf[0]), buf,
*first_digit, precision, first_digit + 2, expo);
} else {
printf("%s\n", buf);
}
}
bar(99994.99, 4);
bar(99995.01, 4);
版画
0.9999E5
0.1000E6
“如果我将精度设置为 4,它不会舍入并给出 0.1234E5,但它应该是 0.1235E5。”
这是因为默认舍入模式是“舍入到最近,并列到偶数”,而 OP 希望“舍入到最近,并列到远”。
base = round(base * pow(10, p)) / pow(10, p);
等代码可能会在 select 情况下实现 OP 的目标,因为此处的乘法和除法可能会由于不精确而导致舍入,有时会在所需的方向上舍入。这在所有 double
中都不可靠,无法实现“舍入到最近,关系到远”。