Десятичное число хранит точность из проанализированной строки в C #?Каковы последствия? - PullRequest
15 голосов
/ 03 января 2012

Во время разговора по IRC кто-то указал на следующее:

decimal.Parse("1.0000").ToString() // 1.0000
decimal.Parse("1.00").ToString() // 1.00

Как / почему тип decimal сохраняет точность (или, скорее, значимые цифры), как это?У меня сложилось впечатление, что эти два значения равны, а не различны.

Это также вызывает дополнительные вопросы:

  • Как определяется число значащих цифр во время математических операций?
  • Сохраняется ли число значащих цифр во время сериализации?
  • Влияет ли текущая культура на то, как это обрабатывается?

Ответы [ 3 ]

9 голосов
/ 03 января 2012

Как определяется число значащих цифр во время математических операций?

Это указано в спецификации ECMA-334 C # 4 11.1.7 с.112

Десятичный знак представлен как целое число, умноженное на степень десять. За десятичные дроби с абсолютным значением менее 1,0 м, значение с точностью до по крайней мере, 28-й знак после запятой. Для десятичных знаков с абсолютным значением больше или равно 1,0 м, значение точно не менее 28 цифры.

Сохраняется ли число значащих цифр во время сериализации?

Да, с сериализацией значение и его точность не меняются

[Serializable]
public class Foo
{
    public decimal Value;
}

class Program
{
    static void Main(string[] args)
    {
        decimal d1 = decimal.Parse("1.0000");
        decimal d2 = decimal.Parse("1.00");

        Debug.Assert(d1 ==d2);

        var foo1 = new Foo() {Value = d1};
        var foo2 = new Foo() {Value = d2};

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new FileStream("data.bin", FileMode.Create, FileAccess.Write, FileShare.None);
        formatter.Serialize(stream, d1);
        stream.Close();

        formatter = new BinaryFormatter();
        stream = new FileStream("data.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
        decimal deserializedD1 = (decimal)formatter.Deserialize(stream);
        stream.Close();

        Debug.Assert(d1 == deserializedD1);

        Console.WriteLine(d1); //1.0000
        Console.WriteLine(d2); //1.00
        Console.WriteLine(deserializedD1); //1.0000

        Console.Read();
    }
}

Влияет ли текущая культура на то, как с этим справляются?

Текущая культура влияет только на то, как десятичное число может быть проанализировано из строки, например, оно может обрабатывать '.' или ',' как символ десятичной точки определенной для культуры или символ валюты, если вы предоставите его, например, "£ 123.4500". Культура не меняет способ хранения объекта внутри и не влияет на его точность.

Внутренне, десятичное число имеет мантиссу, показатель степени и знак, так что места для чего-либо еще нет.

1 голос
/ 03 января 2012

В дополнение к сообщению, которое я вижу здесь, я бы лично добавил примечание:

всегда во время манипуляций с постоянством с плавающей запятой / десятичными / двойными числами учитывайте culture, в котором вы находитесь или собираетесь сохранить. Код, как здесь написано, первый, но окончательный перейти к полному беспорядку и не культурно-независимой архитектуре.

Использовать Decimal.Parse (String, IFormatProvider) .

По моему мнению, методы (Parse From/To), в которых отсутствует параметр Culture, должны быть удалены из библиотеки, чтобы заставить разработчика задуматься над этим очень важным аспектом.

1 голос
/ 03 января 2012

A десятичное число состоит из 96-разрядного целого числа и коэффициента масштабирования (количество цифр после десятичной точки), который находится в диапазоне от 0 до 28. Таким образом:

  • 1.000 становится 1000 с коэффициентом масштабирования 3.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...