Почему делает десятичное число.NET. ToString (строка) вокруг далеко от нуля, по-видимому несовместимого со спецификацией языка?

Я вижу что, в C#, округляясь a decimal, по умолчанию, использование MidpointRounding.ToEven. Это ожидается и - то, что диктует спецификация C#. Однако, учитывая следующее:

  • A decimal dVal
  • Формат string sFmt это при передаче в dVal.ToString(sFmt), приведет к строке, содержащей округленную версию dVal

... это очевидно это decimal.ToString(string) возвращается значение округлило использование MidpointRounding.AwayFromZero. Это, казалось бы, было бы прямым противоречием спецификации C#.

Мой вопрос - это: дело обстоит так существует ли серьезное основание? Или это - просто несоответствие в языке?

Ниже, для ссылки, я включал некоторый код, который пишет для консольного подключения к выбору округления операционных результатов и decimal.ToString(string) операционные результаты, каждый на каждом значении в массиве decimal значения. Эффективные выходные мощности встраиваются. После этого я включал соответствующий абзац от раздела C# Language Specification по decimal ввести.

Пример кода:

static void Main(string[] args)
{
    decimal[] dArr = new decimal[] { 12.345m, 12.355m };

    OutputBaseValues(dArr);
    // Base values:
    // d[0] = 12.345
    // d[1] = 12.355

    OutputRoundedValues(dArr);
    // Rounding with default MidpointRounding:
    // Math.Round(12.345, 2) => 12.34
    // Math.Round(12.355, 2) => 12.36
    // decimal.Round(12.345, 2) => 12.34
    // decimal.Round(12.355, 2) => 12.36

    OutputRoundedValues(dArr, MidpointRounding.ToEven);
    // Rounding with mr = MidpointRounding.ToEven:
    // Math.Round(12.345, 2, mr) => 12.34
    // Math.Round(12.355, 2, mr) => 12.36
    // decimal.Round(12.345, 2, mr) => 12.34
    // decimal.Round(12.355, 2, mr) => 12.36

    OutputRoundedValues(dArr, MidpointRounding.AwayFromZero);
    // Rounding with mr = MidpointRounding.AwayFromZero:
    // Math.Round(12.345, 2, mr) => 12.35
    // Math.Round(12.355, 2, mr) => 12.36
    // decimal.Round(12.345, 2, mr) => 12.35
    // decimal.Round(12.355, 2, mr) => 12.36

    OutputToStringFormatted(dArr, "N2");
    // decimal.ToString("N2"):
    // 12.345.ToString("N2") => 12.35
    // 12.355.ToString("N2") => 12.36

    OutputToStringFormatted(dArr, "F2");
    // decimal.ToString("F2"):
    // 12.345.ToString("F2") => 12.35
    // 12.355.ToString("F2") => 12.36

    OutputToStringFormatted(dArr, "###.##");
    // decimal.ToString("###.##"):
    // 12.345.ToString("###.##") => 12.35
    // 12.355.ToString("###.##") => 12.36

    Console.ReadKey();
}

private static void OutputBaseValues(decimal[] dArr)
{
    Console.WriteLine("Base values:");
    for (int i = 0; i < dArr.Length; i++) Console.WriteLine("d[{0}] = {1}", i, dArr[i]);
    Console.WriteLine();
}

private static void OutputRoundedValues(decimal[] dArr)
{
    Console.WriteLine("Rounding with default MidpointRounding:");
    foreach (decimal d in dArr) Console.WriteLine("Math.Round({0}, 2) => {1}", d, Math.Round(d, 2));
    foreach (decimal d in dArr) Console.WriteLine("decimal.Round({0}, 2) => {1}", d, decimal.Round(d, 2));
    Console.WriteLine();
}

private static void OutputRoundedValues(decimal[] dArr, MidpointRounding mr)
{
    Console.WriteLine("Rounding with mr = MidpointRounding.{0}:", mr);
    foreach (decimal d in dArr) Console.WriteLine("Math.Round({0}, 2, mr) => {1}", d, Math.Round(d, 2, mr));
    foreach (decimal d in dArr) Console.WriteLine("decimal.Round({0}, 2, mr) => {1}", d, decimal.Round(d, 2, mr));
    Console.WriteLine();
}

private static void OutputToStringFormatted(decimal[] dArr, string format)
{
    Console.WriteLine("decimal.ToString(\"{0}\"):", format);
    foreach (decimal d in dArr) Console.WriteLine("{0}.ToString(\"{1}\") => {2}", d, format, d.ToString(format));
    Console.WriteLine();
}


Абзац от раздела 4.1.7 из Спецификации языка C# ("Десятичный тип") (получают полную спецификацию здесь (.doc)):

Результат операции на значениях десятичного числа типа - это, которое следовало бы из вычисления точного результата (сохраняющий масштаб, как определено для каждого оператора) и затем округляющийся для установки представлению. Результаты округлены к ближайшему представимому значению, и, когда результат одинаково близко к двум представимым значениям к значению, которое имеет четное число в наименьшем количестве положения значащей цифры (это известно как округление “банкира”). Нулевой результат всегда имеет знак 0 и масштаб 0.

Легко видеть, что они не могли рассматривать ToString(string) в этом абзаце, но я склонен думать, что он вписывается в это описание.

18
задан John Saunders 12 February 2010 в 03:13
поделиться

3 ответа

ToString () по умолчанию форматирует в соответствии с культурой , а не в соответствии с вычислительным аспектом спецификации. Очевидно, Культура для вашего региона (и, судя по всему, большинства) ожидает округления от нуля.

Если вам нужно другое поведение, вы можете передать IFormatProvider в ToString ()

Я подумал выше, но вы правы, что он всегда округляется от нуля независимо от Культура . Проверьте ссылки в комментариях для подтверждения.

1
ответ дан 30 November 2019 в 09:36
поделиться

http://docs.miktex.org/2.8/relnotes/#id517080

Перейдите в каталог miktex и попробуйте найти mo.exe (параметр Miktex). Исправление: запустите MiKTeX Options и выберите либо Да, либо Нет (но не «Спросите меня сначала») для опции «Установить отсутствующие пакеты на лету».

-121--3894887-

Да, можно с помощью команды inspectdb

python manage.py inspectdb

или

python manage.py inspectdb > models.py

ввести их в файл

. При этом будет рассмотрена база данных, настроенная в settings.py , и выведены классы моделей для стандартного вывода.

Как отметил Игнасио, в документации имеется руководство по вашей ситуации .

-121--1527854-

Если вы внимательно прочитаете спецификацию, вы увидите, что здесь нет противоречий.

Вот этот абзац снова, с выделенными важными частями:

Результатом операции над значениями типа decimal является результат вычисления точного результата (сохранение масштаба, как определено для каждого оператора) и последующего округления в соответствии с представлением. Результаты округляются до ближайшего представимого значения и, когда результат одинаково близок к двум представимым значениям, до значения, которое имеет четное число в позиции наименьшей значащей цифры (это называется «округлением банкира»). Нулевой результат всегда имеет знак 0 и масштаб 0.

Эта часть спецификации применяется к арифметическим операциям в десятичной ; форматирование последовательностей не является одним из них, и даже если бы оно было, это не имело бы значения, потому что ваши примеры малоточны.

Чтобы продемонстрировать поведение, упомянутое в спецификации, используйте следующий код:

Decimal d1 = 0.00000000000000000000000000090m;
Decimal d2 = 0.00000000000000000000000000110m;

// Prints: 0.0000000000000000000000000004 (rounds down)
Console.WriteLine(d1 / 2);

// Prints: 0.0000000000000000000000000006 (rounds up)
Console.WriteLine(d2 / 2);

Вот все, о чем говорит спецификация. Если результат некоторого вычисления превысит предел точности десятичного типа (29 цифр), для определения результата используется округление банкира.

6
ответ дан 30 November 2019 в 09:36
поделиться

Термин, который мне нравится для рамок, библиотечных наборов и некоторых типов инструментов разработки, - это платформенные технологии. Платформенные технологии не только влияют на размер и производительность кода.

  1. Если проект сам по себе предназначен для использования в качестве библиотеки или рамки, вы можете в конечном итоге использовать выбор технологии платформы для разработчиков, использующих вашу библиотеку.

  2. Если вы распространяете проект в исходной форме, вы можете в конечном итоге использовать технологии платформы для конечных пользователей.

  3. Если статически не связать все выбранные рамки и библиотеки, то конечные пользователи могут столкнуться с проблемами управления версиями библиотек.

  4. Компиляция времени влияет на производительность разработчиков. Инкрементная привязка, предварительно скомпилированные заголовки, правильное управление зависимостями заголовков и т.д. могут помочь в управлении временем компиляции, но не устраняют проблемы производительности компилятора, связанные с большим количеством встроенного кода, которые внедряют некоторые технологии платформы.

  5. Для проектов, распространяемых в качестве исходных, время компиляции влияет на конечных пользователей проекта.

  6. Многие платформенные технологии имеют собственные требования к среде разработки. Эти требования могут накапливаться, что затрудняет и требует много времени для новых разработчиков проекта, чтобы иметь возможность реплицировать среду, необходимую для компиляции и отладки.

  7. Использование некоторых технологий платформы фактически создает новый язык программирования для проекта. Это затрудняет участие новых разработчиков.

Все проекты имеют зависимости от технологии платформы, но для многих проектов существует реальная выгода от сведения этих зависимостей к минимуму.

-121--110â6-

Мой ответ может быть не тем, который вы хотели бы, но я бы сказал - не надо. Пока не используйте HTML 5.

-121--3509358-

Скорее всего, потому, что это стандартный способ обращения с валютой. Толчком к созданию десятичной запятой стало то, что плавающая точка плохо справляется со значениями валюты, поэтому можно ожидать, что ее правила будут в большей степени соответствовать стандартам бухгалтерского учета, чем математической корректности.

1
ответ дан 30 November 2019 в 09:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: