Примитивные типы в java

Переполнение

Вопрос: «Что произойдет, если мы попытаемся использовать значение, которое находится вне диапазона значений определенного типа данных?». Ответ: «Переполнение».

Переполнение (англ. «overflow») случается при потере бит из-за того, что переменной не было выделено достаточно памяти для их хранения.

На уроке №28 мы говорили о том, что данные хранятся в бинарном (двоичном) формате и каждый бит может иметь только 2 возможных значения ( или ). Вот как выглядит диапазон чисел от 0 до 15 в десятичной и двоичной системах:

Десятичная система Двоичная система
1 1
2 10
3 11
4 100
5 101
6 110
7 111
8 1000
9 1001
10 1010
11 1011
12 1100
13 1101
14 1110
15 1111

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

Размер основных типов данных в C++

Возникает вопрос: «Сколько памяти занимают переменные разных типов данных?». Вы можете удивиться, но размер переменной с любым типом данных зависит от компилятора и/или архитектуры компьютера!

Язык C++ гарантирует только их минимальный размер:

Категория Тип Минимальный размер
Логический тип данных bool 1 байт
Символьный тип данных char 1 байт
wchar_t 1 байт
char16_t 2 байта
char32_t 4 байта
Целочисленный тип данных short 2 байта
int 2 байта
long 4 байта
long long 8 байт
Тип данных с плавающей запятой float 4 байта
double 8 байт
long double 8 байт

Фактический размер переменных может отличаться на разных компьютерах, поэтому для его определения используют оператор sizeof.

Оператор sizeof — это унарный оператор, который вычисляет и возвращает размер определенной переменной или определенного типа данных в байтах. Вы можете скомпилировать и запустить следующую программу, чтобы выяснить, сколько занимают разные типы данных на вашем компьютере:

#include <iostream>

int main()
{
std::cout << «bool:\t\t» << sizeof(bool) << » bytes» << std::endl;
std::cout << «char:\t\t» << sizeof(char) << » bytes» << std::endl;
std::cout << «wchar_t:\t» << sizeof(wchar_t) << » bytes» << std::endl;
std::cout << «char16_t:\t» << sizeof(char16_t) << » bytes» << std::endl;
std::cout << «char32_t:\t» << sizeof(char32_t) << » bytes» << std::endl;
std::cout << «short:\t\t» << sizeof(short) << » bytes» << std::endl;
std::cout << «int:\t\t» << sizeof(int) << » bytes» << std::endl;
std::cout << «long:\t\t» << sizeof(long) << » bytes» << std::endl;
std::cout << «long long:\t» << sizeof(long long) << » bytes» << std::endl;
std::cout << «float:\t\t» << sizeof(float) << » bytes» << std::endl;
std::cout << «double:\t\t» << sizeof(double) << » bytes» << std::endl;
std::cout << «long double:\t» << sizeof(long double) << » bytes» << std::endl;
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

#include <iostream>

intmain()

{

std::cout<<«bool:\t\t»<<sizeof(bool)<<» bytes»<<std::endl;

std::cout<<«char:\t\t»<<sizeof(char)<<» bytes»<<std::endl;

std::cout<<«wchar_t:\t»<<sizeof(wchar_t)<<» bytes»<<std::endl;

std::cout<<«char16_t:\t»<<sizeof(char16_t)<<» bytes»<<std::endl;

std::cout<<«char32_t:\t»<<sizeof(char32_t)<<» bytes»<<std::endl;

std::cout<<«short:\t\t»<<sizeof(short)<<» bytes»<<std::endl;

std::cout<<«int:\t\t»<<sizeof(int)<<» bytes»<<std::endl;

std::cout<<«long:\t\t»<<sizeof(long)<<» bytes»<<std::endl;

std::cout<<«long long:\t»<<sizeof(longlong)<<» bytes»<<std::endl;

std::cout<<«float:\t\t»<<sizeof(float)<<» bytes»<<std::endl;

std::cout<<«double:\t\t»<<sizeof(double)<<» bytes»<<std::endl;

std::cout<<«long double:\t»<<sizeof(longdouble)<<» bytes»<<std::endl;

return;

}

Вот результат, полученный на моем компьютере:

Ваши результаты могут отличаться, если у вас другая архитектура, или другой компилятор

Обратите внимание, оператор sizeof не используется с типом void, так как последний не имеет размера

Если вам интересно, что значит в коде, приведенном выше, то это специальный символ, который используется вместо клавиши TAB. Мы его использовали для выравнивания столбцов. Детально об этом мы еще поговорим на соответствующих уроках.

Интересно то, что sizeof — это один из 3-х операторов в языке C++, который является словом, а не символом (еще есть new и delete).

Вы также можете использовать оператор sizeof и с переменными:

#include <iostream>

int main()
{
int x;
std::cout << «x is » << sizeof(x) << » bytes» << std::endl;
}

1
2
3
4
5
6
7

#include <iostream>
 

intmain()

{

intx;

std::cout<<«x is «<<sizeof(x)<<» bytes»<<std::endl;

}

Результат выполнения программы:

На следующих уроках мы рассмотрим каждый из фундаментальных типов данных языка С++ по отдельности.

Типы с плавающей точкой

Числа с плавающей точкой (иногда их называют действительными числами) применяются при вычислении выражений, в которых требуется точность до десятичного знака. Например, это может быть вычисление квадратного корня, значений синуса, косинуса и т.п. Существует два типа с плавающей точкой: float и double, которые представляют числа одинарной и двойной точности.

Слово «плавающая» означает, что десятичная точка может располагаться в любом месте (она «плавает»). Вот коты плавать не особенно любят, поэтому они не float и не double.

Тип float

Тип float определяет значение одинарной точности, которое занимает 32 бит. Переменные данного типа удобны, когда требуется дробная часть без особой точности, например, для денежных сумм.

Рекомендуется добавлять символ F или f для обозначения этого типа, иначе число будет считаться типом double.

Конвертируем из строки.

Класс Float является оболочкой для данного типа. Без необходимости не используйте в Android класс Float.

Также есть специальный класс BigDecimal для проведения арифметических действий повышенной точности (финансовые расчёты).

Тип double

Тип double обеспечивает двойную точность, что видно из его названия (double — двойная). Занимает 64 бит для хранения значений. Многие математические функции возвращают значения типа double. Кстати, современные процессоры оптимизированы под вычисления значений двойной точности, поэтому они предпочтительнее, чем тип float.

Тип double содержит не только числа, но и слова. Сейчас вам докажу. Разделим число типа double на ноль. Ошибки не произойдёт.

Пример вернёт значение Infinity (Бесконечность). Если разделить отрицательное число на ноль, то вернётся -Infinity.

А что произойдёт, если сложить две бесконечности? Если рассуждать логически, то сломается интернет, наступит конец света или можно вызвать Волдеморта. Я долго не решался, но потом набрался храбрости и попробовал.

Вернулось ещё одно слово — NaN. Что это вообще? Может должно вернуться Nyan — ну вы знаете, это странный котик, который летит бесконечно в космосе, оставляя за собой шлейф из радуги.

Умножать две бесконечности я побоялся. И вам не советую.

Класс Double является оболочкой для данного типа. Без необходимости не используйте в Android класс Double.

Конвертация double в строку

При работе с числами double следует держать ухо востро. Рассмотрим пример конвертации трёх чисел.

Первые два числа нормально преобразовались, а вот третье число преобразовалось в строку в странном виде (на самом деле это научное представление числа). И это может источником проблемы при передаче строки куда-нибудь, например, на сервер. Если сервер не ожидает от вас такой подлости, то будет генерировать ошибки из-за странной записи. Нужно найти другие способы конвертации.

Первый способ — используем String.format().

Последний пример самый подходящий для нас, но вам нужно знать, сколько знаков идёт после десятичной точки. Остальные два пригодятся, если число можно округлить.

Второй способ — метод Double.toString(). У меня метод превратил число в «непонятную» строку. А у некоторых этот пример возвращал строку в нормальном виде. Не заслуживает доверия.

Третий способ — добавить пустую строку. В Android не помогло, хотя тоже утверждается, что у кого-то выводится в нормальном виде. Врут, наверное.

Четвёртый экзотический способ, которым редко пользуются — DecimalFormat.

Характеристики типов с плавающей запятойCharacteristics of the floating-point types

C# поддерживает следующие предварительно определенные типы с плавающей запятой:C# supports the following predefined floating-point types:

Ключевое слово или тип C#C# type/keyword Приблизительный диапазон значенийApproximate range ТочностьPrecision РазмерSize Тип .NET.NET type
От ±1,5 x 10−45 до ±3,4 x 1038±1.5 x 10−45 to ±3.4 x 1038 6–9 цифр~6-9 digits 4 байта4 bytes System.Single
от ±5,0 × 10−324 до ±1,7 × 10308±5.0 × 10−324 to ±1.7 × 10308 15–17 цифр~15-17 digits 8 байт8 bytes System.Double
от ±1,0 x 10-28 до ±7,9228 x 1028±1.0 x 10-28 to ±7.9228 x 1028 28-29 знаков28-29 digits 16 байт16 bytes System.Decimal

В приведенной выше таблице каждый тип ключевого слова C# из крайнего левого столбца является псевдонимом для соответствующего типа .NET.In the preceding table, each C# type keyword from the leftmost column is an alias for the corresponding .NET type. Они взаимозаменяемые.They are interchangeable. Например, следующие объявления объявляют переменные одного типа:For example, the following declarations declare variables of the same type:

По умолчанию все типы с плавающей запятой имеют значение .The default value of each floating-point type is zero, . Все типы с плавающей запятой имеют константы и с минимальным и максимальными итоговыми значениями этого типа.Each of the floating-point types has the and constants that provide the minimum and maximum finite value of that type. Типы и также предоставляют константы, обозначающие бесконечные и нечисловые значения.The and types also provide constants that represent not-a-number and infinity values. Например, тип предоставляет следующие константы: Double.NaN, Double.NegativeInfinity и Double.PositiveInfinity.For example, the type provides the following constants: Double.NaN, Double.NegativeInfinity, and Double.PositiveInfinity.

Так как тип характеризуется более высокой точностью и меньшим диапазоном, чем и , он подходит для финансовых расчетов.Because the type has more precision and a smaller range than both and , it’s appropriate for financial and monetary calculations.

В одном и том же выражении можно сочетать и целочисленные типы, и типы и .You can mix integral types and the and types in an expression. В этом случае целочисленные типы неявно преобразуются в один из типов с плавающей запятой. При необходимости тип неявно преобразуется в .In this case, integral types are implicitly converted to one of the floating-point types and, if necessary, the type is implicitly converted to . Выражение вычисляется следующим образом.The expression is evaluated as follows:

  • Если в выражении есть тип , оно оценивается как или в реляционных сравнениях или сравнениях на равенство.If there is type in the expression, the expression evaluates to , or to in relational and equality comparisons.
  • Если в выражении нет типа , оно оценивается как или в реляционных сравнениях или сравнениях на равенство.If there is no type in the expression, the expression evaluates to , or to in relational and equality comparisons.

Можно также смешивать целочисленные типы и тип в выражении.You can also mix integral types and the type in an expression. В этом случае целочисленные типы неявно преобразуются в тип , а выражение вычисляется как или в реляционных сравнениях и сравнениях на равенство.In this case, integral types are implicitly converted to the type and the expression evaluates to , or to in relational and equality comparisons.

Тип нельзя смешивать с типами и в выражении.You cannot mix the type with the and types in an expression. В этом случае, если требуется выполнить арифметические операции или операции сравнения или равенства, необходимо явно преобразовать операнды из типа или в тип , как показано в следующем примере:In this case, if you want to perform arithmetic, comparison, or equality operations, you must explicitly convert the operands either from or to the type, as the following example shows:

Можно использовать строки стандартных числовых форматов или строки пользовательских числовых форматов для форматирования значения с плавающей запятой.You can use either standard numeric format strings or custom numeric format strings to format a floating-point value.

Типизация переменных

Именно так работали бы переменные, если бы в не существовало типизации. Типизация – это возможность разделить коробочки по возможному содержимому. То есть, когда мы создаем коробочку, мы кроме имени указываем, что в ней может располагаться. И тогда, в коробочку для IPhone котеночка ты уже не засунешь.

Это позволяет дополнительно защититься от ошибок, потому что ты будешь заранее знать, что будет в коробочке, и будешь готов к тому, как тебе нужно будет себя вести с содержимым.

Языки программирования условно можно разделить на два больших типа:

Сильнотипизированные – те, где вся ответственность за указание типа переменных ложится на программиста

Слаботипизированные – те, где компьютер сам решает, какой тип используется в конкретном случае.

Язык C# относится к первым. Возможно, это лишает его такой гибкости как тот же самый JavaScript (который относится ко вторым), но при этом дает большую защищенность от ошибок.

СинтаксисSyntax

float Где n — это количество битов, используемых для хранения мантиссы числа в формате float при экспоненциальном представлении. Определяет точность данных и размер для хранения.float Where n is the number of bits that are used to store the mantissa of the float number in scientific notation and, therefore, dictates the precision and storage size. Если указан параметр n, это должно быть значение в диапазоне от 1 до 53.If n is specified, it must be a value between 1 and 53. Значение n по умолчанию — 53.The default value of n is 53.

Значение nn value ТочностьPrecision Объем памятиStorage size
1-241-24 7 цифр7 digits 4 байта4 bytes
25-5325-53 15 знаков15 digits 8 байт8 bytes

Примечание

В приложении SQL ServerSQL Server параметр n может принимать одно из двух возможных значений.SQL ServerSQL Server treats n as one of two possible values. Если 1<=n<=24, n принимает значение 24.If 1<=n<=24, n is treated as 24. Если 25<=n<=53, n принимает значение 53.If 25<=n<=53, n is treated as 53.

Тип данных SQL ServerSQL Server float соответствует стандарту ISO для всех значений n в диапазоне от 1 до 53.The SQL ServerSQL Server float data type complies with the ISO standard for all values of n from 1 through 53. Синонимом типа double precision является тип float(53) .The synonym for double precision is float(53).

Примечание

Ссылки на описание синтаксиса Transact-SQL для SQL Server 2014 и более ранних версий, см. в статье .To view Transact-SQL syntax for SQL Server 2014 and earlier, see .

Объявление и инициализация переменных

В общем случае при объявлении переменной в C#, вначале указывается тип данных переменной, затем ее имя:

int nVal;
string strVal;

Задание значения переменной можно произвести в момент инициализации:

int radius = 10;
string name = "John";

либо после инициализаций:

string name;
name = "John";

Необходимо иметь ввиду, что переменную нельзя использовать до тех пор пока она не будет проинициализирована, Например, выполнение следующей программы завершится с ошибкой:

int notInitedVal;
Console.Write(notInitedVal);

В примерах мы не будем приводить код импорта и объявления класса. В конце главы будет приведен листинг программы со всеми примерами из данного урока.

Ключевое слово new

Ключевое слово new, как правило, используется при инициализации переменных, которые имеют ссылочный тип данных. О том, что это такое мы расскажем чуть ниже. Пусть у нас есть класс Rectangle

class Rectangle
{
    public double Width = 0;
    public double Height = 0;
}

Данный класс нам нужен только для демонстрации, при разработке собственных классов не стоит создать поля с ключевым словом public. О создании классов и основах объектно-ориентированного программирования будет рассказано в одном из ближайших уроков.

Создадим переменную класса Rectangle

Rectangle rect = new Rectangle();
Console.WriteLine($"Rectangle Width={rect.Width}, Height={rect.Height}");

Переменные типа int, double и т.п. также можно проинициализировать с помощью ключевого слова new, в этом случае будет присвоено значение по умолчанию:

int newInitedValue = new int();
Console.WriteLine("Default int value: " + newInitedValue);

Ключевое слово var. Неявная типизация

При объявлении переменной вместо явного задания типа можно поставить ключевое слово var. В этом случае будет использована система вывода типов для определения типа переменной по ее значению.

int v1 = 12345;
var v2 = 12345;

Console.WriteLine($"Type of v1: {v1.GetType()}\nType of v2: {v2.GetType()}");

При работе с var необходимо помнить следующее:

  • использовать var можно только для объявления локальных переменных;
  • var нельзя использоваться для объявления типа возвращаемого значения, типов полей и параметров;
  • при объявлении переменной с использованием var она обязательно должна быть проинициализирована, при этом использовать для этого null запрещено;
  • объявлять переменную допускающую null-значение с использованием лексемы ? через var нельзя.

Причины возникновения ошибки

Приоритет и ассоциативность операторовOperator precedence and associativity

В следующем списке перечислены арифметические операторы в порядке убывания приоритета:The following list orders arithmetic operators starting from the highest precedence to the lowest:

  • Постфиксный инкремент и декремент Postfix increment and decrement operators
  • Префиксный инкремент и декремент , унарные операторы и Prefix increment and decrement and unary and operators
  • Мультипликативные операторы , , и Multiplicative , , and operators
  • Аддитивные операторы и Additive and operators

Бинарные арифметические операторы имеют левую ассоциативность.Binary arithmetic operators are left-associative. То есть операторы с одинаковым приоритетом вычисляются в направлении слева направо.That is, operators with the same precedence level are evaluated from left to right.

Порядок вычисления, определяемый приоритетом и ассоциативностью операторов, можно изменить с помощью скобок ().Use parentheses, , to change the order of evaluation imposed by operator precedence and associativity.

Полный список операторов C#, упорядоченный по уровню приоритета, можно найти в разделе статьи Операторы C#.For the complete list of C# operators ordered by precedence level, see the section of the C# operators article.

Типы указателей

Для любого типа T существует тип «указатель на T».

Переменные могут быть объявлены как указатели на значения различных типов с помощью символа . Для того чтобы определить тип переменной как указатель, нужно предварить её имя звёздочкой.

char letterC = 'C';
char *letter = &letterC; //взятие адреса переменной letterC и присваивание в переменную letter
printf("This code is written in %c.", *letter); //"This code is written in C."

Помимо стандартных типов, можно объявлять указатели на структуры и объединения:

struct Point { int x,y; } A;
A.x = 12;
A.y = 34;
struct Point *p = &A;
printf("X: %d, Y: %d", (*p).x, (*p).y); //"X: 12, Y: 34"

Для обращения к полям структуры по указателю существует оператор «стрелочка» , синонимичный предыдущей записи: — то же самое, что и .

Поскольку указатель — тоже тип переменной, правило «для любого типа T» выполняется и для них: можно объявлять указатели на указатели. К примеру, можно пользоваться :

int w = 100;
int *x = &w;
int **y = &x;
int ***z = &y;
printf("w contains %d.", ***z); //"w contains 100."

Существуют также указатели на массивы и на функции. Указатели на массивы имеют следующий синтаксис:

char *pc10]; // массив из 10 указателей на char
char (*pa); // указатель на массив из 10 переменных типа char

 — массив указателей, занимающий байт (на распространённых платформах — обычно 40 или 80 байт), а  — это один указатель; занимает он обычно 4 или 8 байт, однако позволяет обращаться к массиву, занимающему 10 байт: , но .
Указатели на массивы отличаются от указателей на первый элемент арифметикой. Например, если указатели указывает на адрес 2000, то указатель будет указывать на адрес 2010.

char (*pa);
char array10 = "Wikipedia";
pa = &array;
printf("An example for %s.\n", *pa); //"An example for Wikipedia."
printf("%c %c %c", (*pa), (*pa), (*pa)); //"i i i"

Работа с типом doubleWork with the double type

Числовой тип представляет число с плавающей запятой двойной точности.The numeric type represents a double-precision floating point number. Эти термины могут быть новыми для вас.Those terms may be new to you. Число с плавающей запятой можно использовать для представления нецелых чисел, которые могут быть очень большими или малыми.A floating point number is useful to represent non-integral numbers that may be very large or small in magnitude. Число двойной точности — это относительный термин, описывающий количество двоичных разрядов, используемых для хранения значения.Double-precision is a relative term that describes the number of binary digits used to store the value. Числа двойной точности имеют в два раза больше двоичных символов по сравнению с числами одиночной точности.Double precision numbers have twice the number of binary digits as single-precision. На современных компьютерах числа двойной точности используются чаще, чем одиночной.On modern computers, it’s more common to use double precision than single precision numbers. Числа одиночной точности объявляются с помощью ключевого слова .Single precision numbers are declared using the keyword.
Рассмотрим их.Let’s explore. Добавьте следующий код и просмотрите результат:Add the following code and see the result:

Обратите внимание, что ответ включает десятичную долю частного.Notice that the answer includes the decimal portion of the quotient. Попробуйте более сложное выражение с типом double:Try a slightly more complicated expression with doubles:. Диапазон значений типа double гораздо больше, чем диапазон значений целых чисел.The range of a double value is much greater than integer values

Добавьте следующий фрагмент после написанного кода:Try the following code below what you’ve written so far:

Диапазон значений типа double гораздо больше, чем диапазон значений целых чисел.The range of a double value is much greater than integer values. Добавьте следующий фрагмент после написанного кода:Try the following code below what you’ve written so far:

Значения выводятся в экспоненциальном представлении.These values are printed out in scientific notation. Число слева от символа является значащим.The number to the left of the is the significand. Число справа — это показатель степени, который равен 10.The number to the right is the exponent, as a power of 10.

Так же, как десятичные числа в математике, значения double в C# могут содержать ошибки округления.Just like decimal numbers in math, doubles in C# can have rounding errors. Выполните этот код:Try this code:

Вы знаете, что периодическая десятичная дробь не равняется .You know that repeating isn’t exactly the same as .

ЗадачаChallenge

Выполните другие вычисления с большими числами, малыми числами, умножением и делением с помощью типа .Try other calculations with large numbers, small numbers, multiplication, and division using the type. Попробуйте выполнить более сложные вычисления.Try more complicated calculations.

После того как вы решите сложную задачу, поместите написанный код в новый метод.After you’ve spent some time with the challenge, take the code you’ve written and place it in a new method. Присвойте этому методу имя .Name that new method .

Изучение порядка операцийExplore order of operations

Закомментируйте вызов .Comment out the call to . Это поможет упорядочить выходные данные в этом разделе.It will make the output less cluttered as you work in this section:

запускает комментарий в C#.The starts a comment in C#. Комментарии — это любой текст, который должен быть сохранен в исходном коде, но не должен выполняться как код.Comments are any text you want to keep in your source code but not execute as code. Компилятор не создает исполняемый код из комментариев.The compiler doesn’t generate any executable code from comments.

Язык C# определяет приоритет математических операций в соответствии с правилами математики.The C# language defines the precedence of different mathematics operations with rules consistent with the rules you learned in mathematics.
Умножение и деление имеют приоритет над сложением и вычитанием.Multiplication and division take precedence over addition and subtraction.
Чтобы удостовериться в этом, добавьте следующий код в метод и выполните команду :Explore that by adding the following code to your method, and executing :

В выходных данных видно, что умножение выполняется раньше сложения.The output demonstrates that the multiplication is performed before the addition.

Можно применить другую последовательность операций. Для этого операции, которые должны выполняться первыми, нужно заключить в скобки.You can force a different order of operation by adding parentheses around the operation or operations you want performed first. Добавьте приведенные ниже строки и выполните код еще раз.Add the following lines and run again:

Поэкспериментируйте, объединяя различные операции.Explore more by combining many different operations. Добавьте в конец метода строки, подобные приведенным ниже.Add something like the following lines at the bottom of your method. Выполните еще раз.Try again.

Возможно, вы заметили интересное поведение целых чисел.You may have noticed an interesting behavior for integers. Деление целых чисел всегда дает результат в виде целого числа, даже если ожидаемый результат содержит десятичную или дробную часть.Integer division always produces an integer result, even when you’d expect the result to include a decimal or fractional portion.

Если вы еще не видели пример такого поведения, добавьте следующий код в конец метода :If you haven’t seen this behavior, try the following code at the end of your method:

Выполните еще раз, чтобы просмотреть результаты.Type again to see the results.

Прежде чем продолжить, давайте поместив весь код, который вы написали в этом разделе, в новый метод.Before moving on, let’s take all the code you’ve written in this section and put it in a new method. Вызовите этот новый метод .Call that new method .
Результат должен быть примерно таким:You should write something like this:

Что такое переменная?

Определение переменной звучит примерно следующим образом:

Переменная – это именованная область памяти.

Но что это означает для нас. Давайте разбираться на примере.

Я думаю, что каждый из вас уже знаком с понятием переменной в алгебре. Это тот самый X, который приходиться искать в уравнении. В программировании переменная имеет схожие функции. Это своеобразный псевдоним, что-то неопределенное, неизвестное, под которым может скрываться кто угодно

Представь себе коробочку. На этой коробочке написано «Подарок» и это делает эту коробочку уникальной. Ты всегда сможешь найти именно эту коробку по этому имени (при условии, что не может существовать ни одной другой коробочки с таким именем).

А вот положить в эту коробочку ты можешь все что угодно. Это может быть и новенький IPhone, и миленький котеночек, и что-нибудь куда менее приятное (как в фильме «Семь»). Кстати, если не смотрел этот фильм, очень рекомендую, но только если у тебя крепкая психика и тебе больше 18 лет.

И в дальнейшем ты можешь как угодно работать с этой коробочкой. В любой момент ты можешь положить туда что-нибудь (предварительно выкинув оттуда то, что там лежало раньше), посмотреть, что там лежит, или вообще взять и выкинуть эту коробочку со всем содержимым.

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

Ошибки округления

Рассмотрим дробь 1/10. В десятичной системе счисления эту дробь можно представить, как 0.1. В двоичной системе счисления эта дробь представлена в виде бесконечной последовательности — 0.00011001100110011… Именно из-за подобных разногласий в представлении чисел в разных системах счисления, у нас могут возникать проблемы с точностью. Например:

#include <iostream>
#include <iomanip> // для std::setprecision()

int main()
{
double d(0.1);
std::cout << d << std::endl; // используем точность cout по умолчанию (6 цифр)
std::cout << std::setprecision(17);
std::cout << d << std::endl;
return 0;
}

1
2
3
4
5
6
7
8
9
10
11

#include <iostream>
#include <iomanip> // для std::setprecision()

intmain()

{

doubled(0.1);

std::cout<<d<<std::endl;// используем точность cout по умолчанию (6 цифр)

std::cout<<std::setprecision(17);

std::cout<<d<<std::endl;

return;

}

Результат выполнения программы:

Первый cout выводит (что и ожидаемо). После того, как мы изменили для объекта cout точность вывода до 17 цифр, мы увидели, что значением переменной является не совсем ! Подобное происходит из-за ограничений в количестве выделяемой памяти для переменных типа double, а также из-за необходимости «округлять» числа. По факту мы получили типичную ошибку округления.

Подобные ошибки могут иметь неожиданные последствия:

#include <iostream>
#include <iomanip> // для std::setprecision()

int main()
{
std::cout << std::setprecision(17);

double d1(1.0);
std::cout << d1 << std::endl;

double d2(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1); // должно получиться 1.0
std::cout << d2 << std::endl;
}

1
2
3
4
5
6
7
8
9
10
11
12
13

#include <iostream>
#include <iomanip> // для std::setprecision()

intmain()

{

std::cout<<std::setprecision(17);

doubled1(1.0);

std::cout<<d1<<std::endl;

doubled2(0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1);// должно получиться 1.0

std::cout<<d2<<std::endl;

}

Результат выполнения программы:

Хотя мы ожидали, что и окажутся равными, но это не так. А что, если бы нам довелось сравнивать эти переменные и, исходя из результата, выполнять определенный сценарий? В таком случае ошибок нам не миновать.

Математические операции (например, сложение или умножение), как правило, только увеличивают масштаб этих ошибок. Даже если имеет погрешность в 17-й значащей цифре, то при выполнении операции сложения десять раз, ошибка округления переместится к 16-й значащей цифре.

2 Целые типы

В языке Java аж 4 целых типа: , , и . Они отличаются размером и диапазоном значений, которые могут хранить.

Тип

Самым часто используемым является тип . Его название происходит от Integer (целый). Все целочисленные литералы в коде имеют тип (если в конце числа не указана буква , или ).

Переменные этого типа могут принимать значение от до .

Это достаточно много и хватает почти для всех случаев жизни. Почти все функции, которые возвращают число, возвращают число типа .

Примеры:

Код Пояснение
Метод возвращает длину строки
Поле содержит длину массива.

Тип

Тип получил свое название от . Его еще называют короткое целое. В отличие от типа , его длина всего два байта и возможный диапазон значений от до .

То есть в нем даже число миллион не сохранишь. Даже 50 тысяч. Это самый редко используемый целочисленный тип в Java. В основном его используют, когда хотят сэкономить на памяти.

Допустим, у вас ситуация, когда заранее известно, что значения с которыми вы работаете не превышает 30 тысяч, и таких значений миллионы.

Например, вы пишете приложение, которое обрабатывает картинки сверхвысокой четкости: на один цвет приходится бит. А точек у вас в картинке — миллион. И вот тут уже играет роль, используете вы тип или .

Тип

Этот тип получил свое название от — его еще называют длинное целое. В отличие от типа , у него просто гигантский диапазон значений: от до

Почему же он не является основным целым типом?

Все дело в том, что Java появилась еще в середине 90-х, когда большинство компьютеров были 32-х разрядными. А это значило, что все процессоры были заточены под работу с числами из 32-х бит. С целыми числами из 64-х бит процессоры работать уже умели, но операции с ними были медленнее.

Поэтому программисты разумно решили сделать стандартным целым типом тип , ну а тип использовать только тогда, когда без него действительно не обойтись.

Тип

Это самый маленький целочисленный тип в Java, но далеко не самый редко используемый. Его название совпадает со словом — минимальная адресуемая ячейка памяти в Java.

Размер допустимых значений типа не так уж велик: от до . Но не в этом его сила. Тип чаще всего используется, когда нужно хранить в памяти большой блок обезличенных данных. Массив типа просто идеально подходит для этих целей.

Например, вам нужно куда-то скопировать файл.

Вам не нужно обрабатывать содержимое файла: вы просто хотите создать область памяти (буфер), скопировать в нее содержимое файла, а затем записать эти данные из буфера в другой файл. Массив типа — то, что нужно для этих целей.

Тем более, что в переменной-типа-массив хранится только ссылка на область памяти. При передаче значения этой переменной в какой-то метод произойдет только передача адреса в памяти, а сам блок памяти копироваться на будет.

Деление целочисленных переменных

В языке C++ при делении двух целых чисел, где результатом является другое целое число, всё довольно предсказуемо:

#include <iostream>

int main()
{
std::cout << 20 / 4 << std::endl;
return 0;
}

1
2
3
4
5
6
7

#include <iostream>

intmain()

{

std::cout<<204<<std::endl;

return;

}

Результат:

Но что произойдет, если в результате деления двух целых чисел мы получим дробное число? Например:

#include <iostream>

int main()
{
std::cout << 8 / 5 << std::endl;
return 0;
}

1
2
3
4
5
6
7

#include <iostream>

intmain()

{

std::cout<<85<<std::endl;

return;

}

Результат:

В языке C++ при делении целых чисел результатом всегда будет другое целое число. А такие числа не могут иметь дробь (она просто отбрасывается, не округляется!).

Рассмотрим детально вышеприведенный пример: . Но как мы уже знаем, при делении целых чисел результатом является другое целое число. Таким образом, дробная часть () значения отбрасывается и остается .

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector