如何将固定精度的两倍格式化为给定的长度
How to format a double of fixed precision to a given length?
我正在使用格式的输出,例如
std::cout << " " << std::setw(7) << std::setprecision(5) << Value ;
准备桌子的目标。但是,表似乎是这样:
0 6.0303 16.052 40.523 100 40.557 16.167 6.7314 1.8967 0
0 4.5593 13.16 25.342 41.927 25.354 13.312 4.9988 1.9527 0
0 3.0952 6.6864 13.531 17.01 13.544 6.7291 3.466 0.91553 0
0 1.1353 3.466 5.0842 7.3242 5.0842 3.4981 1.2207 0.56076 0
0 0.54474 0.95825 2.153 2.1179 2.153 0.95825 0.5928 0.10681 0
0 0.085449 0.38452 0.45166 0.78392 0.45166 0.38452 0.085449 0.048065 0
0 0.032043 0.042725 0.15221 0.11444 0.15221 0.042725 0.032043 0 0
0 0 0 0 0 0 0 0 0 0
看起来小数点之后的第一个数字为零,则显示长度更长。我如何避免它?
使用:
std::cout << std::fixed;
默认行为是在"精度"中显示数字数。STD ::固定是显示精确的数字数量。因此,默认情况下您将显示5个重要数字。在固定的5个数字上。
例如:
auto a = 2017.0;
default = 2017
fixed = 2017.00000
auto b = 1e-10;
default= 1e-10
fixed = 0.00000
hm。因此,我想在考虑所有边缘案例后要这样做。我敢肯定,我不处理一些正确的事,我认为这在C中会更干净,但是我认为这还可以(如果经过工程的方式(。
如果您知道发生了什么,请随时用评论进行编辑:(。
除了一些警告:
这已经超过了工程,并且经过测试。
不是便携式的,但可以通过更多的工作来制作。
我在您的输入中添加了额外的测试/角案。
这可能比您需要的要多,但是您可以将其推广。或使用更好的库。
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <vector>
const std::vector<std::vector<double>> array = {
// OP's data.
{0, 6.0303, 16.052, 40.523, 100, 40.557, 16.167, 6.7314, 1.8967, 0},
{0, 4.5593, 13.16, 25.342, 41.927, 25.354, 13.312, 4.9988, 1.9527, 0},
{0, 3.0952, 6.6864, 13.531, 17.01, 13.544, 6.7291, 3.466, 0.91553, 0},
{0, 1.1353, 3.466, 5.0842, 7.3242, 5.0842, 3.4981, 1.2207, 0.56076, 0},
{0, 0.54474, 0.95825, 2.153, 2.1179, 2.153, 0.95825, 0.5928, 0.10681, 0},
{0, 0.085449, 0.38452, 0.45166, 0.78392, 0.45166, 0.38452, 0.085449, 0.048065, 0},
{0, 0.032043, 0.042725, 0.15221, 0.11444, 0.15221, 0.042725, 0.032043, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// My test data.
{1e-7, 1.12031e-34, 1e-34, 1e-6, 1e33, 1e-8, 1.3123233e93, 1e32, 1.e99, 1.e100},
{-1e-7, -1.12031e-34, -1e-34, -1e-6, -1e33, -1e-8, -1.3123233e93, -1e32, -1.e99, -1.09e100},
};
// Warning: any widths under 7 cannot accurately print the double -1e+100...
// (or many like it). There's just no way to express that any more tersely!
constexpr uint8_t kWidth = 7;
// Most of these are really obvious but help make the code slightly cleaner.
// "."
constexpr uint8_t kWidthTakenByDecimalSeparator = 1;
// "-"
constexpr uint8_t kWidthTakenByNegativeSign = 1;
// "e+" or "e-"
constexpr uint8_t kWidthOfExtraScientificNotationCharacters = 2;
// On *MY* system, 1.0e-08 is always printed, not 1.0e-8. This basically handles
// the leading 0 on the exponent. Tune accordingly (or find the right compiler
// flags that give you the right number(s).
constexpr uint8_t kMinimumWidthOfScientificNotationExponent = 2;
int main() {
// Store the original std::cout flags.
auto old_flags = std::cout.flags();
for (auto& row : array) {
for (auto& value : row) {
const double log10_value = log10(std::abs(value));
const uint8_t available_width = kWidth - (value < 0) * kWidthTakenByNegativeSign;
// Handle numbers greater than 10^kWidth or less than 10^-kWidth in
// scientific notation.
const bool use_scientific_notation =
value != 0 &&
(log10_value < -1.0 * available_width + kWidthTakenByDecimalSeparator +
kWidthTakenByNegativeSign ||
log10_value > available_width);
std::cout << ' ' << std::setw(kWidth);
if (use_scientific_notation) {
const double log10log10_value = log10(log10_value);
const uint8_t num_digits_in_exponent_of_scientific_notation =
std::max(kMinimumWidthOfScientificNotationExponent,
static_cast<uint8_t>(log10log10_value ));
const uint8_t num_digits_desired_after_decimal_scientific =
std::max(1.0, log10log10_value);
uint8_t potential_new_precision =
available_width - num_digits_in_exponent_of_scientific_notation -
kMinimumWidthOfScientificNotationExponent -
kWidthTakenByDecimalSeparator -
num_digits_desired_after_decimal_scientific;
// Lazy underflow checking. Needed?
if (potential_new_precision > available_width) {
potential_new_precision = 0;
}
std::cout << std::scientific
<< std::setprecision(potential_new_precision);
} else {
// We take the max with 1.0 to compensate for the leading 0 in decimals.
// If your system doesn't put a leading zero there, remove it.
const uint8_t number_of_digits_before_decimal_fixed =
std::max(log10_value + 1.0, 1.0);
const uint8_t number_of_digits_desired_after_decimal_fixed =
available_width - kWidthTakenByDecimalSeparator -
number_of_digits_before_decimal_fixed;
// Fixed width decimals -- this means that the code
// std::cout << std::precision(n)
// tells the stream to use n digits *after the decimal*.
std::cout << std::fixed
<< std::setprecision(
number_of_digits_desired_after_decimal_fixed);
}
std::cout << value;
}
std::cout << 'n';
}
// Reset the flags to their old value, and flush the output buffer.
std::cout.flush();
std::cout.flags(old_flags);
}
和有趣的东西:
用kwidth = 7:
输出示例0.00000 6.03030 16.0520 40.5230 100.000 40.5570 16.1670 6.73140 1.89670 0.00000
0.00000 4.55930 13.1600 25.3420 41.9270 25.3540 13.3120 4.99880 1.95270 0.00000
0.00000 3.09520 6.68640 13.5310 17.0100 13.5440 6.72910 3.46600 0.91553 0.00000
0.00000 1.13530 3.46600 5.08420 7.32420 5.08420 3.49810 1.22070 0.56076 0.00000
0.00000 0.54474 0.95825 2.15300 2.11790 2.15300 0.95825 0.59280 0.10681 0.00000
0.00000 0.08545 0.38452 0.45166 0.78392 0.45166 0.38452 0.08545 0.04806 0.00000
0.00000 0.03204 0.04272 0.15221 0.11444 0.15221 0.04272 0.03204 0.00000 0.00000
0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000
1.0e-07 1.1e-34 1.0e-34 1.0e-06 1.0e+33 1.0e-08 1.3e+93 1.0e+32 1.0e+99 1e+100
-1e-07 -1e-34 -1e-34 -1e-06 -1e+33 -1e-08 -1e+93 -1e+32 -1e+99 -1e+100
示例输出kwidth = 10:
0.00000000 6.03030000 16.0520000 40.5230000 100.000000 40.5570000 16.1670000 6.73140000 1.89670000 0.00000000
0.00000000 4.55930000 13.1600000 25.3420000 41.9270000 25.3540000 13.3120000 4.99880000 1.95270000 0.00000000
0.00000000 3.09520000 6.68640000 13.5310000 17.0100000 13.5440000 6.72910000 3.46600000 0.91553000 0.00000000
0.00000000 1.13530000 3.46600000 5.08420000 7.32420000 5.08420000 3.49810000 1.22070000 0.56076000 0.00000000
0.00000000 0.54474000 0.95825000 2.15300000 2.11790000 2.15300000 0.95825000 0.59280000 0.10681000 0.00000000
0.00000000 0.08544900 0.38452000 0.45166000 0.78392000 0.45166000 0.38452000 0.08544900 0.04806500 0.00000000
0.00000000 0.03204300 0.04272500 0.15221000 0.11444000 0.15221000 0.04272500 0.03204300 0.00000000 0.00000000
0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
0.00000010 1.1203e-34 1.0000e-34 0.00000100 1.0000e+33 0.00000001 1.3123e+93 1.0000e+32 1.0000e+99 1.000e+100
-0.0000001 -1.120e-34 -1.000e-34 -0.0000010 -1.000e+33 -1.000e-08 -1.312e+93 -1.000e+32 -1.000e+99 -1.09e+100
那比我想象的要多。
相关文章:
- 重复使用预分配的向量<复杂<double>>作为<double>长度两倍的向量
- 计算C++两倍的差值
- 为什么当我进入退出条件时,程序会打印两倍的默认条件而不是退出 while 循环?
- 内存移动的性能与memcpy相比是两倍?
- Qt 是 JSON 精度的两倍
- 不完整的多线程光线追踪器花费的时间是预期的两倍
- C++随机函数给出的相同整数是输出的两倍
- 为什么我的最终向量是它应该大小的两倍并且具有前导 0?
- 为什么即使在从int到两倍的类型施放后,小数也没有小数
- 如何将固定精度的两倍格式化为给定的长度
- getsockopt() 返回的值是之前由 setsockopt() 设置的值的两倍
- MF SinkWriter mp4文件的播放持续时间是添加音频样本时的一半,图像的播放速度也是添加音频样本的两倍
- 无论如何,是否可以使用setCursorPos(int,int)函数,但没有采用两个int使它需要速度较慢的两倍
- 是一个包含两个INT(只有两个INT)的结构,保证是大小(INT)的两倍
- C++ "time.h"测量的运行时间是实际值的两倍
- 退出申请致电两倍
- SSE42 & STTNI - PcmpEstrM比PcmpIstrM慢两倍,是真的吗?
- 在同一台机器上,是否保证两倍值的不精确性是一致的
- 处理数据的方法,速度是我处理速度的两倍
- C++11 getline 要求输入的两倍