powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / decimal.ToString() trim trailing zeros
11 сообщений из 11, страница 1 из 1
decimal.ToString() trim trailing zeros
    #39124515
Фотография Ex_Soft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
static void Main(string[] args)
{
      decimal
          decimalVictimI = 1.123456789010000m,
          decimalVictimII = 1.12345678901m;

      string
          decimalVictimIStr = decimalVictimI.ToString(), // "1.123456789010000"
          decimalVictimIIStr = decimalVictimII.ToString(); // "1.12345678901"
}


Почему, посмотрев IL, становится понятно:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
..method private hidebysig static void  Main(string[] args) cil managed
{
   .entrypoint
   // Code size       39 (0x27)
   .maxstack  6
   .locals init ([0] valuetype [mscorlib]System.Decimal decimalVictimI,
            [1] valuetype [mscorlib]System.Decimal decimalVictimII)
   IL_0000:  nop
   IL_0001:  ldc.i4     0x2ad45650
   IL_0006:  ldc.i4     0x3fdc7
   IL_000b:  ldc.i4.0
   IL_000c:  ldc.i4.0
   IL_000d:  ldc.i4.s   15
   IL_000f:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32,
                                                                      int32,
                                                                      int32,
                                                                      bool,
                                                                      uint8)
   IL_0014:  stloc.0
   IL_0015:  ldc.i4     0x28530435
   IL_001a:  ldc.i4.s   26
   IL_001c:  ldc.i4.0
   IL_001d:  ldc.i4.0
   IL_001e:  ldc.i4.s   11
   IL_0020:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32,
                                                                      int32,
                                                                      int32,
                                                                      bool,
                                                                      uint8)
   IL_0025:  stloc.1
   IL_0026:  ret
} // end of method Program::Main


decimal рожается посредством Decimal Constructor (Int32, Int32, Int32, Boolean, Byte)
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
public Decimal(int lo, int mid, int hi, bool isNegative, byte scale)
{
     if (scale > 0x1c)
     {
         throw new ArgumentOutOfRangeException("scale", Environment.GetResourceString("ArgumentOutOfRange_DecimalScale"));
     }
     this.lo = lo;
     this.mid = mid;
     this.hi = hi;
     this.flags = scale << 0x10;
     if (isNegative)
     {
         this.flags |= -2147483648;
     }
}


(BTW, decimal.Parse() тоже правильно выставляет scale). И вот, союзно этому scale, Decimal.ToString()
Код: c#
1.
2.
3.
4.
public override string ToString()
{
     return Number.FormatDecimal(this, null, NumberFormatInfo.CurrentInfo);
}


и возвращает значение за'PadRight'ченное нулями.
Дык к чему это все: можно ли как-то по умному заставить decimal "пересчитать" scale/flag? В контексте setter'а... Учитывая, что
Код: c#
1.
2.
Console.WriteLine("decimalVictimI {0}= decimalVictimII", decimalVictimI == decimalVictimII ? "=" : "!");
Console.WriteLine("{0}decimal.Equals(decimalVictimI, decimalVictimII)", decimal.Equals(decimalVictimI, decimalVictimII) ? string.Empty : "!");


Или только посредством чего-то а-ля
Код: c#
1.
decimalVictimI = decimal.Parse(decimalVictimI.ToString().TrimEnd(new[] {'0'}));


Можно, конечно, еще заюзать Decimal.GetBits() по умному, анализируя, scale и т.д. и т.п.
Но, мо, ЭстЪ что-то более вменяемое?

_________________
"Helo, word!" - 17 errors 56 warnings
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124585
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ex_SoftИли только посредством чего-то а-ля
Код: c#
1.
decimalVictimI = decimal.Parse(decimalVictimI.ToString().TrimEnd(new[] {'0'}));


Нездоровый способ. В итоге две строки и массив символов создадутся и в мусор пойдут.
И криво отработает при
Код: c#
1.
decimalVictimI = 123000m



Пытался порешать этот же вопрос. В итоге перешел на double. У double ToString() без лишних нулей.

PS Если нет потребности в точности более 15 десятичных знаков, то double достаточно.
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124600
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TPS Если нет потребности в точности более 15 десятичных знаков, то double достаточно.

грабли ждут тебя
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124620
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилDima TPS Если нет потребности в точности более 15 десятичных знаков, то double достаточно.

грабли ждут тебя
Если ты про равенство, то я в курсе.
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124685
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
при работе с double равенство вообще лучше не делать, только неравенство по модулю разницы с погрешностью
а вообще на работе часто сталкиваемся с этой проблемой, особенно когда данные надо импортнуть из Oracle в MS и обратно, в результате можно такого нагрузить
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124713
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TЕсли ты про равенство, то я в курсе.
нет, я о накоплении погрешности
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124743
Фотография Axeleron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TИзопропилпропущено...


грабли ждут тебя
Если ты про равенство, то я в курсе.
Почитайте внимательно о double и decimal. Double не гаранирует точности после запятой. Там грабли не в точности более 15 десятичных знаков.
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124751
Фотография Ex_Soft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TИ криво отработает при

Ну дык...
Ex_SoftИли только посредством чего-то а-ля

Знамо дело, что там поумнее надоть а-ля

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
         static class DecimalExtensions
         {
             public static decimal Normalize(this decimal value)
             {
                 if (value == 0)
                     return value;

                 var parts = Decimal.GetBits(value);

                 if ((byte)((parts[3] >> 16) & 0x7F) == 0)
                     return value;

                 var valueStr = value.ToString(CultureInfo.InvariantCulture);

                 //if (valueStr.IndexOf(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator, StringComparison.InvariantCulture) == -1)
                 //    return value;

                 var regex = new Regex(string.Format("(?<={0}\\d+)0+$", Regex.Escape(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)));

                 return regex.IsMatch(valueStr) ? decimal.Parse(regex.Replace(valueStr, string.Empty), CultureInfo.InvariantCulture) : value;
             }
         }


Но это, тем паче на setter'е, еще хуже
Dima TНездоровый способ. В итоге две строки и массив символов создадутся и в мусор пойдут.


BTW, судя по google не один я был озадачен сим...

_________________
"Helo, word!" - 17 errors 56 warnings
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124856
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AxeleronПочитайте внимательно о double и decimal. Double не гаранирует точности после запятой.
Тогда уж можно заявлять что вообще не гарантирует, т.к. точка там стоит после первого двоичного знака.

вики
Число двойной точности (Double precision, Double)

...
Окончательное значение числа равняется знак * ( 1 +мантисса/ 2^52) * 2^(порядок - 1023)
ИМХУ не надо путать с float с которым эти проблемы были актуальны.


У double мантисса 52 бита, т.е. максимум 2^52 = 4.5*10^15 вот откуда цифра 15 знаков взялась. И не важно до или после запятой. Первые 15 десятичных знаков будут хранится точно.

Точность 100% нужна только в денежном учете (т.е. в рублях). И то только при сложении и вычитании (еще при умножении на целое, но это тоже что и N сложений). Дальше начинаются погрешности из-за округления до копеек. Например: возьми практически любую счет-фактуру из 3-5 строк и проверь что в итого Сумма НДС = Сумма с НДС * Ставка НДС. Не сойдется на копейки. А если сойдется, то сложив построчно Сумму НДС не сойдется с итого Сумма НДС.
Т.е. как только начинается деление (или умножение на дробное) то об абсолютной точности можно забыть. decimal не спасет от округлений при выводе.
Изопропилнет, я о накоплении погрешности
Это надо много-много точных действий (сложение и вычитание) сделать чтобы погрешность исказила хотя бы на копейку результат в рублях. Или результат должен быть 15 знаков. Например сложить все входящие платежи в Сбербанк за год.
Если грубо прикинуть, кол-во операций не менее 10^(16 - макс.разрядность), т.е. например для получении ошибки при сложении до миллиарда надо сложить минимум 100000 значений. Ситуация конечно возможная, но очень редкая.
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124874
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ex_SoftЗнамо дело, что там поумнее надоть а-ля
Код: c#
1.
2.
3.
4.
5.
         static class DecimalExtensions
         {
             public static decimal Normalize(this decimal value)
             {
...


ИМХУ лучше так
Код: c#
1.
public static string ToStringNormalize(this decimal value)


Это же для вывода надо. Чего там у decimal внутри в остальных случаях фиолетово. Так будет сгенерена только одна строка, и там где это надо, т.е. пойдет дальнейшую работу, а не сразу в мусор.
...
Рейтинг: 0 / 0
decimal.ToString() trim trailing zeros
    #39124968
Фотография Ex_Soft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TИМХУ лучше так
Код: c#
1.
public static string ToStringNormalize(this decimal value)


Это же для вывода надо. Чего там у decimal внутри в остальных случаях фиолетово. Так будет сгенерена только одна строка, и там где это надо, т.е. пойдет дальнейшую работу, а не сразу в мусор.
Дык в том-то и засада, что этот Decimal.ToString() юзают далее везде применительно к моей decimal property.

_________________
"Helo, word!" - 17 errors 56 warnings
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / decimal.ToString() trim trailing zeros
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]