Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.83/6: Рейтинг темы: голосов - 6, средняя оценка - 4.83
1 / 1 / 0
Регистрация: 05.04.2015
Сообщений: 15
1

Целочисленные литералы и суффиксы, как правильно это функционирует?

02.07.2015, 01:40. Показов 1186. Ответов 7
Метки нет (Все метки)

Всем доброго времени суток, снова непонимание, и неудача при поиске ответа, HELP!

Имею следующий пример:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Inches
{
    public static void Main()
    {
        long inches;
        int miles;
 
        miles = 93000000;
 
        Console.WriteLine(miles);
 
        inches = miles * 5280 * 12;
 
        Console.WriteLine("Расстояние составляет "+inches);
    }
    
};
Результат :
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." - Это верное утверждение? И что в таком случае происходит если я к примеру не буду явно определять тип для литералов с плавающей запятой?

Вот следующий вариант:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Inches
{
    public static void Main()
    {
        long inches;
        int miles;
 
        miles = 93000000;
 
        Console.WriteLine(miles);
 
        inches = miles * 5280 * 12L;
 
        Console.WriteLine("Расстояние составляет "+inches);
    }
    
};
Результат :
93000000
Расстояние составляет -215130112
Для продолжения нажмите любую клавишу . . .


В данном случае ответ тоже не верный, получается у нас что 5280 это int а 12 я определил как long.


Так, продолжаю значит я дальше:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Inches
{
    public static void Main()
    {
        long inches;
        int miles;
 
        miles = 93000000;
 
        Console.WriteLine(miles);
 
        inches = miles * 5280L * 12;
 
        Console.WriteLine("Расстояние составляет "+inches);
    }
    
};
Результат :
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

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.07.2015, 01:40
Ответы с готовыми решениями:

Можно ли сравнивать строковые литералы? как правильно это сделать?
надо сравнить введенный строковый литерал с одним из доступных. int main() { setlocale(0,""); ...

Целочисленные литералы
Здравствуйте. Читаю книгу и не понятно в одном месте. Написано: целочисленные литералы...

Windows07 не правильно функционирует
открыл программу с помощью MSW07 теперь все открывается с MSW07,помогите ,что делать???

Как это реализовать? И как это правильно называется?
Всем привет. Хочу достигнуть такого эффекта как на этом сайте http://www.kocha.com.au/ Суть...

7
5647 / 2150 / 632
Регистрация: 11.04.2015
Сообщений: 3,626
Записей в блоге: 43
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
Эксперт .NET
15369 / 11652 / 3056
Регистрация: 17.09.2011
Сообщений: 19,501
02.07.2015, 18:58 4
Лучший ответ Сообщение было отмечено ArtemHelloWorld как решение

Решение

Цитата Сообщение от ArtemHelloWorld Посмотреть сообщение
Если возникают операции с разными типами данных, получается что результат приводиться к типу, который имеет больший размер.
Не совсем.
Как сказал выше товарищ diadiavova, операторы — это не более чем функции, со своими параметрами и возвращаемыми значениями.
В шарпе по умолчанию имеется четыре оператора умножения над целочисленными типами:
C#
1
2
3
4
int operator *(int x, int y);
uint operator *(uint x, uint y);
long operator *(long x, long y);
ulong operator *(ulong x, ulong y);
Или, если угодно, так:
C#
1
2
3
4
int Multiply(int x, int y);
uint Multiply(uint x, uint y);
long Multiply(long x, long y);
ulong Multiply(ulong x, ulong y);
Переписываем ваш первый пример:
C#
1
inches = Multiply(Multiply(miles, 5280), 12);
Дальше вступает в дело резолюция перегрузок.
Для того, чтобы определить тип первого параметра внешнего вызова Multiply, надо определить перегрузку внутреннего вызова.
miles — int, 5280 — int, лучший подходящий метод — вот этот:
C#
1
int Multiply(int x, int y);
Возвращает он int, значит тип первого параметра — инт.
12 — тоже инт, значит перегрузка внешнего вызова больше всего подходит такая же:
C#
1
int Multiply(int x, int y);
Результат, как видно, int. Результат высчитывается и значение присваивается переменной inches, попутно конвертиремое в ее тип long.

Второй пример:
C#
1
inches = Multiply(Multiply(miles, 5280), 12L);
Тот же самый процесс: miles — int, 5280 — int, выбирается первая перегрузка, которая возвращает тип int.
Дальше определяется перегрузка внешнего метода: результат внутреннего Multiply — int, 12L — long.
Первая перегрузка не подходит, т.к. второй параметр типа long неявно не конвертируется в int.
Вторая перегрузка не подходит, т.к. ни первый, ни второй параметры не конвертируются неявно в uint.
Третья перегрузка подходит, т.к. первый параметр int конвертируется в long, а второй параметр — уже long.
Четвертая перегрузка не подходит, т.к. ни один из параметров не конвертируется неявно в ulong.

Из списка выше получается только одна подходящая перегрузка — это третья:
C#
1
long Multiply(long x, long y);
Результат первого умножения конвертируется в long и передается в метод вместе с аргументом 12L, метод возвращает long, который и присваивается переменной inches.

Третий пример:
C#
1
inches = Multiply(Multiply(miles, 5280L), 12);
Опять двадцать пять: сначала определяется тип первого аргумента, для чего нужно определить подходящую перегрузку внутреннего вызова. Аргументы: miles — int, 5280L — long.
Как и в предыдущем примере, выбор падает на третью перегрузку, т.к. к ней подходят оба аргумента:
C#
1
long Multiply(long x, long y);
Метод возвращает long, значит тип первого параметра внешнего вызова — long.
Дальше делается то же самое для внешнего вызова:
Результат внутреннего вызова — long, второй аргумент 12 — int.
Опять перегрузка выпадает на третью, она выполняется, возвращаемое значение типа long присваивается переменной inches.
3
5647 / 2150 / 632
Регистрация: 11.04.2015
Сообщений: 3,626
Записей в блоге: 43
02.07.2015, 19:46 5
Цитата Сообщение от ArtemHelloWorld Посмотреть сообщение
Получается что первым делом обращаем внимание на приоритет оператора и/или на скобки (если они есть в выражении)
В данном случае на ассоциативность. Одним словом: всегда надо понимать последовательность выполнения действий. А еще лучше - писать так, чтобы она была очевидной и легко читалась.
Цитата Сообщение от ArtemHelloWorld Посмотреть сообщение
к типу, который имеет больший размер.
Тут не только в размере дело, просто бывают сужающие преобразования, а бывают расширяющие. Сужающее преобразование потенциально может привести к потере данных, поэтому предпочтение отдается преобразованиям расширяющим. В принципе 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 литерал должен быть такого же типа, как и единственный в левой. Верно ли это?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
class Inches
{
    public static void Main()
    {
        ulong inches;
        int miles;
 
        miles = 93000000;
 
        Console.WriteLine(miles);
 
        inches = (ulong)miles * 5280 * 12;
 
        Console.WriteLine("Расстояние составляет " + inches);
    }
 
};
0
Эксперт .NET
15369 / 11652 / 3056
Регистрация: 17.09.2011
Сообщений: 19,501
22.05.2016, 21:49 8
Цитата Сообщение от Дамир_84 Посмотреть сообщение
в правой части хотя бы 1 литерал должен быть такого же типа, как и единственный в левой. Верно ли это?
Не обязательно.
Например:
C#
1
byte x = 124 + 3;
Справа оба литерала — инты, а результат — байт.

C#
1
uint x = -20 + 40;
Справа оба литерала — инты, а результат — беззнаковый инт.

C#
1
2
3
byte a = 12;
byte b = 20;
byte c = a + b;
А вот это уже работать не будет, хотя обе переменные — byte, но результат будет int.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
22.05.2016, 21:49

Как посмотреть суффиксы CSS-классов модулей в шаблоне?
Скажите пожалуйста, как посмотреть суффиксы CSS-классов модулей в шаблоне? В демо-шаблона они не...

Как это правильно называется?
Добрый день, как это правильно называется (хочу почитать про это поподробнее в интернете, но не...

Как это правильно называется
ИмяИнтерфейса название= new КлассКоторыйРеализует(); Это ведь полиформизм в каком то роде? По...

Как это правильно реализовать
Осуществить циклический сдвиг элементов квадратной матрицы размером М х N вправо на k элементов...

как это правильно написать?
Помогите пожалуста! у меня есть две колонки данных (dolar evro) у Мемо как мне достать данные из...

Как использовать строковые литералы в XAML
Помогите, после WinForm хочу в метке отпечатать текст со вставкой новой строки и возвратом каретки,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.