Nie mam problemu z zamianą dubletu na taki ciąg: 7.8746137240E-008

Nie wiem, jak wymusić, aby pierwsza cyfra zawsze była zerem: 0,7874613724E-007

Jak to osiągnąć za pomocą niestandardowego formatu ciągu w C#?

0
RaceRalph 15 czerwiec 2021, 09:34

4 odpowiedzi

Najlepsza odpowiedź

Znalazłem proste rozwiązanie:

value.ToString("\\0.0000000000E+000;-\\0.0000000000E+000")
1
RaceRalph 15 czerwiec 2021, 09:40

Może zrób to sam ;)

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);
1
Klamsi 15 czerwiec 2021, 08:44

Możesz to zrobić, formatując za pomocą standardowej notacji wykładniczej, po której następuje przetwarzanie końcowe:

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));
}

To rozwiązanie jest lepsze niż rozwiązanie @MarkSouls, ponieważ nie cierpi z powodu niedokładności zmiennoprzecinkowej i/lub przepełnienia do nieskończoności wykonywania value * 10. Wymaga to .NET Standard 2,1 i dlatego nie działa z .NET Framework, chociaż można go zmodyfikować, aby działał z nim (kosztem przydzielenia dodatkowej tablicy ciągów i znaków).

1
JosephDaSilva 15 czerwiec 2021, 14:49

Nie znam wymyślnego sposobu na osiągnięcie tego, czego chcesz, ale możesz to zrobić, pisząc własną funkcję.

public static class Extender
{
    public static string MyToString(this double value)
    {
        string s = (value * 10).ToString("E");
        s = s.Replace(".", "");
        return "0." + s;
    }
}

Po prostu modyfikuje się liczbę wykładniczą i przesuwa . do przodu, a następnie dodaje 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
*/

Niezbyt fajny kod, ale działa, chociaż nie sprawdzałem skrajnych przypadków.

Zastanawiam się, czy jest na to bardziej formalny sposób.

0
MarkSouls 15 czerwiec 2021, 07:03