1 / 1 / 0
Регистрация: 05.04.2015
Сообщений: 15
|
||||||||||||||||
1 | ||||||||||||||||
Целочисленные литералы и суффиксы, как правильно это функционирует?02.07.2015, 01:40. Показов 1394. Ответов 7
Метки нет (Все метки)
Всем доброго времени суток, снова непонимание, и неудача при поиске ответа, HELP!
Имею следующий пример:
93000000 Расстояние составляет -215130112 Для продолжения нажмите любую клавишу . . . Результат вычислений неправильный, на сколько я понимаю ошибка вызвана тем что значениям 5280 и 12 был автоматически присвоен тип Int. Вывод я такой сделал из этого комментария полученного методом гугль "Per MSDN "When an integer literal has no suffix, its type is the first of these types in which its value can be represented": int, uint, long, ulong." - Это верное утверждение? И что в таком случае происходит если я к примеру не буду явно определять тип для литералов с плавающей запятой? Вот следующий вариант:
93000000 Расстояние составляет -215130112 Для продолжения нажмите любую клавишу . . . В данном случае ответ тоже не верный, получается у нас что 5280 это int а 12 я определил как long. Так, продолжаю значит я дальше:
93000000 Расстояние составляет 5892480000000 Для продолжения нажмите любую клавишу . . . Собственно тут ответ верный, причем разница с предыдущем листингом состоит только в том, что я определил уже 5280 как long, а 12 не трогал (на сколько я понял он в данном случае числиться как int). Ну и в последнем случае, я ставлю суффикс L и около 12 и около 5280, результат получаю верный. Если утверждение "Per MSDN "When an integer literal has no suffix, its type is the first of these types in which its value can be represented": int, uint, long, ulong." верное, тогда я понимаю природу ошибки, однако я совсем не понимаю как конкретно происходят вычисления и преобразования типов. И как в результате получаются такие значения . Был бы очень рад если бы кто-то объяснил как точно происходят вычисления в каждом примере и как правильно поступать в таких случаях. Также интересует ситуация с плавающей точкой. P.S. Либо дайте хотя бы ссылочку где можно порыться. А еще меня интересует почему преобразование начинается с int, а не с byte and sbyte ведь так место вроде же экономиться?
0
|
02.07.2015, 01:40 | |
Ответы с готовыми решениями:
7
Можно ли сравнивать строковые литералы? как правильно это сделать? Целочисленные литералы Windows07 не правильно функционирует Как это реализовать? И как это правильно называется? |
02.07.2015, 10:22 | 2 |
Для каждого числового типа определены собственные арифметические операторы. Надеюсь не надо объяснять, что оператор - это просто функция, имеющая инфиксную форму записи. Как любая функция, оператор имеет собственную сигнатуру, то есть в нем определен тип операндов и для числовых типов операторы определены таким образом, что принимают оба операнда одного типа, то есть нет оператора умножения, в котором один операнд был бы инт, а другой лонг. Понимая это обстоятельство, несложно понять как, когда и почему происходит преобразование из инт в лонг. Происходит оно тогда и в тех операторах, когда операторам передаются разнотипные операнды. То есть в тех местах, где тип операндов разный, один из операторов будет преобразован к другому типу.
Теперь рассмотрим ситуации, приведенные в примерах. int*int*long Поскольку умножение - левоассоциативный оператор, стало быть вычисление производится слева-направо. То есть сначала выполняется умножение инт-ов, а потом, при выполнении второго оператора уже результат первого вычисления приводится к типу лонг. int*long*int Здесь с самого начала операнды разнотипные, поэтому в первом операторе буед выполнено преобразование первого операнда к типу лонг, а во втором - то же самое будет сделано со вторым операндом. Ошибка же появляется из-за переполнения значения инт. То есть если бы результат первого умножения не превышал максимального значения типа инт, то ошибки бы вообще не было.
2
|
1 / 1 / 0
Регистрация: 05.04.2015
Сообщений: 15
|
|
02.07.2015, 18:33 [ТС] | 3 |
diadiavova, Спасибо, в принципе понятно. Вот только хотел уточнить.
Получается что первым делом обращаем внимание на приоритет оператора и/или на скобки (если они есть в выражении), таким образом получаем последовательность действий. Исходя из этой последовательности можем выяснить типы данных участвующих в операции (int*long, int*int). Ключевой момент, если я правильно понял, заключается в 2 особенностях: 1. Последовательность операторов. 2. Если возникают операции с разными типами данных, получается что результат приводиться к типу, который имеет больший размер. (int*long*int). (int*long > результат в long), (long(он же результат предыдущей операции)*int > результат в long). Поправьте пожалуйста, если что не так понял.
0
|
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
|
||||||||||||||||||||||||||||||||||||||||||||||
02.07.2015, 18:58 | 4 | |||||||||||||||||||||||||||||||||||||||||||||
Сообщение было отмечено ArtemHelloWorld как решение
Решение
Не совсем.
Как сказал выше товарищ diadiavova, операторы — это не более чем функции, со своими параметрами и возвращаемыми значениями. В шарпе по умолчанию имеется четыре оператора умножения над целочисленными типами:
Для того, чтобы определить тип первого параметра внешнего вызова Multiply, надо определить перегрузку внутреннего вызова. miles — int, 5280 — int, лучший подходящий метод — вот этот:
12 — тоже инт, значит перегрузка внешнего вызова больше всего подходит такая же:
Второй пример:
Дальше определяется перегрузка внешнего метода: результат внутреннего Multiply — int, 12L — long. Первая перегрузка не подходит, т.к. второй параметр типа long неявно не конвертируется в int. Вторая перегрузка не подходит, т.к. ни первый, ни второй параметры не конвертируются неявно в uint. Третья перегрузка подходит, т.к. первый параметр int конвертируется в long, а второй параметр — уже long. Четвертая перегрузка не подходит, т.к. ни один из параметров не конвертируется неявно в ulong. Из списка выше получается только одна подходящая перегрузка — это третья:
Третий пример:
Как и в предыдущем примере, выбор падает на третью перегрузку, т.к. к ней подходят оба аргумента:
Дальше делается то же самое для внешнего вызова: Результат внутреннего вызова — long, второй аргумент 12 — int. Опять перегрузка выпадает на третью, она выполняется, возвращаемое значение типа long присваивается переменной inches.
3
|
02.07.2015, 19:46 | 5 |
В данном случае на ассоциативность. Одним словом: всегда надо понимать последовательность выполнения действий. А еще лучше - писать так, чтобы она была очевидной и легко читалась.
Тут не только в размере дело, просто бывают сужающие преобразования, а бывают расширяющие. Сужающее преобразование потенциально может привести к потере данных, поэтому предпочтение отдается преобразованиям расширяющим. В принципе kolorotur все очень подробно расписал, что происходит в данном случае, так что, кроме этих небольших пояснений добавить особо нечего.
1
|
1 / 1 / 0
Регистрация: 05.04.2015
Сообщений: 15
|
|
02.07.2015, 19:58 [ТС] | 6 |
kolorotur, diadiavova, Спасибо, теперь все(!) понятно стало.
0
|
0 / 0 / 0
Регистрация: 20.05.2016
Сообщений: 3
|
||||||
22.05.2016, 20:14 | 7 | |||||
Я решил проблему вот так, возможно более простым является просто помнить, что в правой части хотя бы 1 литерал должен быть такого же типа, как и единственный в левой. Верно ли это?
0
|
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
|
||||||||||||||||
22.05.2016, 21:49 | 8 | |||||||||||||||
Не обязательно.
Например:
0
|
22.05.2016, 21:49 | |
22.05.2016, 21:49 | |
Помогаю со студенческими работами здесь
8
Как посмотреть суффиксы CSS-классов модулей в шаблоне? Как это правильно называется? Как это правильно называется Как это правильно реализовать как это правильно написать? Как использовать строковые литералы в XAML Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |