我通过移植一些传统的C ++代码来获取C#,并希望保持输出相同。曾经是
的内容output << std::setprecision(10) << (double) value;
我认为现在是
output.Write("{0:F10}", value);
但这并没有成功。具体来说,值> 1
会获得更多数字。一个常见的在线建议是先Math.Round
,但如果总长度为< 10
,则会附加零。
所以我把它放在一起:
// std::setprecision is not exactly the same as ":F10", mirror original behavior
static string setPrecision(double value) {
string ret = value.ToString();
// Don't just Substring(0, 11), we need to apply rounding,
// and don't always do this, we don't want to append zeroes,
// for 10 digits + period, with 0.. not counting for total
if(ret.Length > digits + 1)
ret = Math.Round(value, digits + (value < 1 ? 1 : 0) - ret.IndexOf('.')).ToString();
return ret;
}
其中digits
是一个静态常量;我当然可以把它变成一个变量,但对于这个项目来说,这样做是没有意义的。
尽管如此,这似乎过于复杂。是否有更优雅的方式来获得传统行为?
根据要求提供了一些示例I / O
// C++
double test = 0; out << std::setprecision(10);
test = 0.123456780; out << test << '\n';
test = 0.0123456781; out << test << '\n';
test = 0.11234567819; out << test << '\n';
test = 1.00234567899; out << test << '\n';
// C#
double test = 0;
test = 0.123456780; output.WriteLine(setPrecision(test));
test = 0.0123456781; output.WriteLine(setPrecision(test));
test = 0.11234567819; output.WriteLine(setPrecision(test));
test = 1.00234567899; output.WriteLine(setPrecision(test));
两者都产生:
0.12345678
0.0123456781
0.1123456782
1.002345679
同时我注意到所有标题零点似乎都不计入总数而不仅仅是第一个;
// C++
test = 0.012345678906; out << test << '\n'; // 0.01234567891
test = 0.0012345678906; out << test << '\n'; // 0.001234567891
test = 0.00012345678906; out << test << '\n'; // 0.0001234567891
// C#
test = 0.012345678906; output.WriteLine(setPrecision(test)); // 0.0123456789
test = 0.0012345678906; output.WriteLine(setPrecision(test)); // 0.0012345679
test = 0.00012345678906; output.WriteLine(setPrecision(test)); // 0.0001234568
如果没有更直接的解决方案,我必须纠正错误。
答案 0 :(得分:6)
听起来您只想打印具有特定有效位数的数字。您只需使用G格式字符串指定要使用的位数即可。
output.Write("{0:G10}", value);
答案 1 :(得分:3)
您所指的是significant figures。实际上很容易计算:
public static string FormatSignificantFigures(double number, int figures)
{
int e = 0;
while (number >= 10.0)
{
e += 1;
number /= 10;
}
while (number < 1.0)
{
e -= 1;
number *= 10;
}
figures--;
number = Math.Round(number, figures);
figures += 0 - e;
while (e > 0)
{
number *= 10;
e -= 1;
}
while (e < 0)
{
number /= 10;
e += 1;
}
if (figures < 0)
{
figures = 0;
}
return number.ToString($"f{figures}");
}
基本上,前两个while
循环将我们的数字规范化为[1,10)
之间的值。
然后,我们将数字四舍五入到有效数字的数量(减去1,记住我们前面已经有了1
的重要数字。然后我们恢复它,最后一行是C#6.0字符串插值:
return number.ToString("f" + figures);
测试代码是:
public static void _Main(string[] args)
{
double[] numbers = new double[] { 0.012345678906, 0.0012345678906, 0.00012345678906, 0.123456789012, 1.234567890124, 12.345678901234, 123.45678901234, 1234.5678901234, 12345.678901234 };
foreach (double number in numbers)
{
Console.WriteLine($"{number}: {FormatSignificantFigures(number, 3)}");
}
}
结果:
0.012345678906: 0.0123 0.0012345678906: 0.00123 0.00012345678906: 0.000123 0.123456789012: 0.123 1.234567890124: 1.23 12.345678901234: 12.3 123.45678901234: 123 1234.5678901234: 1230 12345.678901234: 12300
注意:这是一个快速的答案,我要将其中的一部分提取到另一个暂时不返回字符串的函数中,但这应该可以让你开始。