C# 指数格式:强制第一个数字为零
C# exponential format: force the first digit to be zero
我可以将双精度数转换为这样的字符串:7.8746137240E-008
我不知道如何强制第一个数字始终为零:0.7874613724E-007
如何在 C# 中使用自定义字符串格式来实现?
我不知道有什么奇特的方法可以实现你想要的,但你可以通过编写自己的函数来实现。
public static class Extender
{
public static string MyToString(this double value)
{
string s = (value * 10).ToString("E");
s = s.Replace(".", "");
return "0." + s;
}
}
它只是修改指数计数并将 .
移到前面然后添加 0。
public static void Main(string[] args)
{
Console.WriteLine(1d.MyToString());
Console.WriteLine(3.14159.MyToString());
Console.WriteLine(0.0033.MyToString());
Console.WriteLine(999414128.0.MyToString());
}
/* Output
0.1000000E+001
0.3141590E+001
0.3300000E-002
0.9994141E+009
*/
虽然我没有检查边缘情况,但代码不是很酷,但它可以工作。
不知道有没有更正式的方法呢
您可以通过使用标准指数符号进行格式化,然后进行一些 post- 处理来做到这一点:
public static string FormatNumberExpZero(double value, IFormatProvider format = null) {
if (!double.IsFinite(value)) // Infinity and NaN
return value.ToString(format);
// Format the number to a temporary buffer.
// "E10" means exponential notation with 10 decimal places.
Span<char> buffer = stackalloc char[24];
value.TryFormat(buffer, out int charCount, "E10", format);
// Don't touch any negative sign.
Span<char> bufferNoSign = (buffer[0] == '-') ? buffer.Slice(1) : buffer;
// Move everything after '.' one character forward to make space for the additional zero.
bufferNoSign.Slice(2, charCount - 2).CopyTo(bufferNoSign.Slice(3));
charCount++;
// Change 'X.' to '0.X'
bufferNoSign[2] = bufferNoSign[0];
bufferNoSign[1] = '.';
bufferNoSign[0] = '0';
// Read the exponent from the buffer.
Span<char> expChars = buffer.Slice(charCount - 4, 4);
int exponent = (expChars[1] - '0') * 100 + (expChars[2] - '0') * 10 + expChars[3] - '0';
if (expChars[0] == '-')
exponent = -exponent;
// Add 1 to the exponent to compensate.
exponent++;
// Write the new exponent back.
expChars[0] = (exponent < 0) ? '-' : '+';
int expAbs = (exponent < 0) ? -exponent : exponent;
int expDigit1 = expAbs / 100;
int expDigit2 = (expAbs - expDigit1 * 100) / 10;
int expDigit3 = expAbs - expDigit1 * 100 - expDigit2 * 10;
Console.WriteLine((expDigit1, expDigit2, expDigit3));
expChars[1] = (char)(expDigit1 + '0');
expChars[2] = (char)(expDigit2 + '0');
expChars[3] = (char)(expDigit3 + '0');
// Create the string.
return new string(buffer.Slice(0, charCount));
}
此解决方案优于@MarkSouls 的解决方案,因为它不会遭受浮点不准确and/or 溢出到无穷大的影响value * 10
。这需要 .NET Standard 2.1,因此不适用于 .NET Framework,但可以对其进行修改以使用它(以分配额外的字符串和字符数组为代价)。
也许自己做 ;)
double foo = 7.8746137240E-008;
var numOfDigits = foo == 0 ? 0 : (int)Math.Ceiling(Math.Log10(Math.Abs(foo)));
string formatString = string.Format("{0:0.000000}E{1:+000;-000;+000}", foo / Math.Pow(10, numOfDigits), numOfDigits);
我找到了一个简单的解决方案:
value.ToString("\0.0000000000E+000;-\0.0000000000E+000")
我可以将双精度数转换为这样的字符串:7.8746137240E-008
我不知道如何强制第一个数字始终为零:0.7874613724E-007
如何在 C# 中使用自定义字符串格式来实现?
我不知道有什么奇特的方法可以实现你想要的,但你可以通过编写自己的函数来实现。
public static class Extender
{
public static string MyToString(this double value)
{
string s = (value * 10).ToString("E");
s = s.Replace(".", "");
return "0." + s;
}
}
它只是修改指数计数并将 .
移到前面然后添加 0。
public static void Main(string[] args)
{
Console.WriteLine(1d.MyToString());
Console.WriteLine(3.14159.MyToString());
Console.WriteLine(0.0033.MyToString());
Console.WriteLine(999414128.0.MyToString());
}
/* Output
0.1000000E+001
0.3141590E+001
0.3300000E-002
0.9994141E+009
*/
虽然我没有检查边缘情况,但代码不是很酷,但它可以工作。
不知道有没有更正式的方法呢
您可以通过使用标准指数符号进行格式化,然后进行一些 post- 处理来做到这一点:
public static string FormatNumberExpZero(double value, IFormatProvider format = null) {
if (!double.IsFinite(value)) // Infinity and NaN
return value.ToString(format);
// Format the number to a temporary buffer.
// "E10" means exponential notation with 10 decimal places.
Span<char> buffer = stackalloc char[24];
value.TryFormat(buffer, out int charCount, "E10", format);
// Don't touch any negative sign.
Span<char> bufferNoSign = (buffer[0] == '-') ? buffer.Slice(1) : buffer;
// Move everything after '.' one character forward to make space for the additional zero.
bufferNoSign.Slice(2, charCount - 2).CopyTo(bufferNoSign.Slice(3));
charCount++;
// Change 'X.' to '0.X'
bufferNoSign[2] = bufferNoSign[0];
bufferNoSign[1] = '.';
bufferNoSign[0] = '0';
// Read the exponent from the buffer.
Span<char> expChars = buffer.Slice(charCount - 4, 4);
int exponent = (expChars[1] - '0') * 100 + (expChars[2] - '0') * 10 + expChars[3] - '0';
if (expChars[0] == '-')
exponent = -exponent;
// Add 1 to the exponent to compensate.
exponent++;
// Write the new exponent back.
expChars[0] = (exponent < 0) ? '-' : '+';
int expAbs = (exponent < 0) ? -exponent : exponent;
int expDigit1 = expAbs / 100;
int expDigit2 = (expAbs - expDigit1 * 100) / 10;
int expDigit3 = expAbs - expDigit1 * 100 - expDigit2 * 10;
Console.WriteLine((expDigit1, expDigit2, expDigit3));
expChars[1] = (char)(expDigit1 + '0');
expChars[2] = (char)(expDigit2 + '0');
expChars[3] = (char)(expDigit3 + '0');
// Create the string.
return new string(buffer.Slice(0, charCount));
}
此解决方案优于@MarkSouls 的解决方案,因为它不会遭受浮点不准确and/or 溢出到无穷大的影响value * 10
。这需要 .NET Standard 2.1,因此不适用于 .NET Framework,但可以对其进行修改以使用它(以分配额外的字符串和字符数组为代价)。
也许自己做 ;)
double foo = 7.8746137240E-008;
var numOfDigits = foo == 0 ? 0 : (int)Math.Ceiling(Math.Log10(Math.Abs(foo)));
string formatString = string.Format("{0:0.000000}E{1:+000;-000;+000}", foo / Math.Pow(10, numOfDigits), numOfDigits);
我找到了一个简单的解决方案:
value.ToString("\0.0000000000E+000;-\0.0000000000E+000")