#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. Это действительно интересно и легко понять. Большое спасибо!