Почему .0 отбрасывается в делении, но не в , — и *?

#c# #.net #integer #decimal

Вопрос:

Итак, в соответствии с правилами C#, в подразделении (int amp; int division) выводом является int. Находясь в (подразделении FP и int), это FP.

но следующие генерируют разные результаты.

 int a = 45; //integer
decimal b = 5.0m; //floating point
Console.WriteLine(a/b); // "9"
 

Вывод: 9 //вывод выглядит как целое число??? почему?

Обратите внимание, что , -, и * дают ожидаемый результат:

   Console.WriteLine(a * b); // "225.0"
 

Деление на не целое число дает ожидаемый результат:

 int a = 45; //integer
decimal b = 5.5m; //floating point
Console.WriteLine(a/b); // "8.181818181818181818"
 

Вывод: 8.18181818181818181818 — / вывод-это FP, который в порядке.

Кто-нибудь может это объяснить?

Результаты более последовательны для float / double — без нулей в выводе для всех операций (что имеет смысл, поскольку эти типы не хранят информацию о количестве цифр после десятичной точки).

Комментарии:

1. output is an integer — нет. вывод представляет собой строковое представление числа — в обоих случаях. если вам нужен определенный формат, используйте string.Format() — например. также: каков, по-вашему, будет результат? 9.0 ? 9.00 ? 9.000 ? … (подсказка: сохраните результат вашего разделения в переменной и проверьте его с помощью отладчика)

2. Я ожидал, что это будет «9.0», так как 5.0 был с плавающей запятой, точно так же, как 5.5, который генерирует выходные данные с плавающей запятой без использования какой-либо строки. Формат() Я учил своего ученика общему правилу для «оператора деления». Но я понятия не имею, почему он усекает ноль в 9.0 P.S. Я учитель и впервые преподаю C#.

3. как учитель, вы должны знать, что математически 9 это равно 9.0 и 9.00000000000000000000000000000000... . поэтому программа выбирает самый короткий. точно так же, как это печатается 5.5 вместо 5.50000 (или, например, 05.5 ). кроме того, и я не хочу вас обидеть, но я считаю, что было бы разумным шагом лучше понять основы C#, прежде чем преподавать его? документация по C# — отличное место для начала.

4. @FranzGleichmann пожалуйста, обратите внимание, что в вопросе используется decimal и 5m отличается от 5.0m — поэтому очень справедливо ожидать, что результат деления сохранит «одну цифру после десятичной точки». Так что, хотя этот вопрос выглядит абсолютно глупо, на самом деле у него есть веские причины для существования.

5. Я не думаю, что полезно думать в терминах значений «с плавающей запятой» или «не с плавающей запятой». Все они являются значениями с плавающей запятой. Речь идет либо о том, «сколько значащих цифр сохраняется», либо о том, «сколько десятичных знаков сохраняется».

Ответ №1:

Стандарт C# подробно описан здесь, в разделе 12.9.3.

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

Итак, чтобы применить это, у нас есть x значение 45 м (после неявного преобразования в decimal ), которое имеет масштаб 0 и 5.0m которое имеет масштаб 1.

Поэтому предпочтительная шкала -1, что было бы недопустимым. (Шкала всегда неотрицательна.) Ближайшая шкала, которая может сохранить точный результат, равна 0, так что это фактический масштаб — результат эквивалентен 9m , а не 9.0m .

Комментарии:

1. Извините, но было бы очень любезно с вашей стороны взглянуть на пример 2 в моем обновлении и объяснить, почему использование 45,0 м дает результат 9,0, но использование 5,0 м в примере PO дает результат 9?

2. @Serge: 45.0 имеет шкалу 1, 5 имеет шкалу 0, поэтому «предпочтительная шкала» равна 1, что дает результат 9,0. (Я объяснил, почему 45/5.0 возвращает 9 в ответе — это будет иметь отрицательную предпочтительную шкалу, поэтому он использует 0 в качестве ближайшей шкалы, которая действительна и все еще дает правильный точный результат.)

3. Спасибо, мне жаль, что я, должно быть, дурак, но я все еще не понимаю этого, так как для меня пример PO выглядит одинаково для меня — 5,0 м имеет шкалу 1, 45 имеет шкалу 0, поэтому «предпочтительная шкала» равна 1, что дает результат 9,0, но это дает результат 9. Единственная разница в том, что у них противоположные роли.

4. И если попробовать int a = 45; десятичное число b = 5.000 m; у вас все равно будет a/b=9, а не 9.000

5. @Serge: Вы вычитаете масштаб не в ту сторону. Предпочтительная шкала такова scale(x) - scale(y) , поэтому 45/5.0 имеет предпочтительную шкалу -1 , а не 1. Аналогично, 45/5 000 м имеет предпочтительную шкалу -3 .

Ответ №2:

Я протестировал и получил такой результат

 int a = 45; //integer
    decimal b = 5.0m; //floating point
    var r=a/b; // r is decimal
    Console.WriteLine(r);  // 9


 a = 45; //integer
     b = 5.5m; //decimal floating point
     r=a/b;   // r is decimal
    Console.WriteLine(r);  // 8.181818181818181818181818182
 

как я мог видеть в отладчике, в обоих классах вывод был десятичным, а не целым в первом случае тоже

Компилятор выполняет неявное преобразование, если результат явно не определен в коде. Существует множество способов приведения типов. Основное правило здесь таково: «если в выражении несколько операндов, то тип результата является наибольшим из типов операндов». Например, если вы разделите int и double, результат будет двойным. Если вы умножите байт и int, результат будет int.

Больше примеров ( теперь с умножением)

     int a = 45; //integer
    
    decimal b = 5.0m; //floating point
    var rm = a*b; // rm is decimal
    Console.WriteLine(rm);  // 225.0
        
    b = 5.5m; //decimal floating point
    var r2m = a*b; // r2m is decimal
    Console.WriteLine(r2m);  // 247.5
 

Обновить

Поскольку вопрос был значительно изменен @AlexeiLevenkov, и он спрашивает меня в комментариях, почему .0 исключен из разделения, эти примеры показывают, что это не так

  int a = 5; //integer


 decimal b = 45m; //floating point
 var r= b/a; // r is decimal
Console.WriteLine(r);  //  9


 b = 45.0m; //floating point
  r= b/a; // r is decimal
Console.WriteLine(r);  //  9.0

 b = 45.00m; //floating point
 var r= b/a; // r is decimal
Console.WriteLine(r);  //  9.00

 b = 45.000m; //floating point
 var r= b/a; // r is decimal
Console.WriteLine(r);  //  9.000
 

Эти примеры показывают, что по умолчанию коэффициент имеет такое же значение, как и дивиденды.

ОБНОВЛЕНИЕ 2

если вы попытаетесь это сделать, вы получите сообщение об ошибке «Не удается неявно преобразовать десятичный тип в int

 int r = a/b; // error!!!
 

но это нормально

 int r = a/(int)b; 
 

и это тоже нормально

 decimal r = a/b; 
 

Комментарии:

1. Спасибо, я сделал это и получил решение/ответ, почему он генерирует такой вывод.

2. Если вы добавите объяснение вывода Console.WriteLine(a*b); ответа, это будет действительно потрясающе… Без этого это действительно лишь частичный ответ… даже если @Amy получит то, что они хотели.

3. @AlexeiLevenkov Хорошо, проверьте мой ответ еще раз

4. Это пример, а не объяснение — нет никаких оснований, почему он печатает «225.0», а не «225», как вы могли бы видеть float (мне действительно интересно, есть ли на самом деле формальное объяснение поведения подразделения… Я могу разумно понять, почему другие операции сохраняют десятичную точность)

5. @AlexeiLevenkov «9 или 9.0» Почему это так важно для вас? Я вообще не имею никакого практического применения и не оказываю никакого влияния на какой-либо код

Ответ №3:

 int a = 45; //integer
decimal b = 5.0m; //floating point
Console.WriteLine(a/b); // why "9" and not 9.0 right?
 

Итак, если я спрошу вас, что бы вы умножили на 5,0, чтобы получить 45? Вы скажете 9 или 9.0?

Говоря языком непрофессионала, частное сохраняется как целое число, если не существует остатка.

Теперь давайте посмотрим, что уникального в десятичной системе счисления.

 double x = 10.0d; // is 10
 

Но

 decimal x = 10.0m; //is 10.0 
 

Формула для десятичной дроби : x.0m is x.0 and xm is x

Формула для двойного/плавающего : x.0d or xd is x

Теперь, применяя приведенную выше формулу, рассмотрим эти случаи …

10.0 d 10.0 d 10.0 d ( x.0d is x )

10 10 10 = 30

10,0 d 10,1 d 10,0 d ( x.0d is x )

10 10.1 10 = 30.1

45 * 5,0 d ( x.0d is x )

45 * 5 = 255

Но…

10,0 м 10,0 м 10,0 м ( x.0m is x.0 )

10.0 10.0 10.0 = 30.0

10,0 м 10,1 м 10,0 м ( x.0m is x.0 )

10.0 10.1 10.0 = 30.1

45 * 5,0 м ( x.0m is x.0 )

45 * 5.0 = 255.0

45 * 5 м ( xm is x )

45 * 5 = 255

Теперь подумайте о процессе разделения…

Его делитель * (коэффициент(0… /-n)) до тех пор, пока остаток не станет 0 или меньше делителя

45/5,0 м

5,0 м * 1 м..2 м..3 м…9 м, а остаток здесь становится 0. конец. последнее частное равно 9м.

Но 9м-это все равно 9, а не 9,0, верно?

Комментарии:

1. Это действительно интересно и легко понять. Большое спасибо!