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")