Перейти к содержимому

Как сравнить float с 0

  • автор:

Числовые типы с плавающей запятой (справочник по C#)

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

Характеристики типов с плавающей запятой

C# поддерживает следующие предварительно определенные типы с плавающей запятой:

Ключевое слово или тип C# Приблизительный диапазон значений Точность Размер Тип .NET
float От ±1,5 x 10 −45 до ±3,4 x 10 38 6–9 цифр 4 байта System.Single
double от ±5,0 × 10 −324 до ±1,7 × 10 308 15–17 цифр 8 байт System.Double
decimal от ±1,0 x 10 -28 до ±7,9228 x 10 28 28-29 знаков 16 байт System.Decimal

В приведенной выше таблице каждый тип ключевого слова C# из крайнего левого столбца является псевдонимом для соответствующего типа .NET. Они взаимозаменяемые. Например, следующие объявления объявляют переменные одного типа:

double a = 12.3; System.Double b = 12.3; 

По умолчанию все типы с плавающей запятой имеют значение 0 . Все типы с плавающей запятой имеют константы MinValue и MaxValue с минимальным и максимальными итоговыми значениями этого типа. Типы float и double также предоставляют константы, обозначающие бесконечные и нечисловые значения. Например, тип double предоставляет следующие константы: Double.NaN, Double.NegativeInfinity и Double.PositiveInfinity.

Тип decimal подходит, если требуемая степень точности определяется числом цифр справа от десятичной запятой. Такие числа обычно используются в финансовых приложениях для денежных сумм (например, 1,00 долл. США), процентных ставок (например, 2,625 %) и т. д. Даже числа, точные только до одной десятичной цифры, точнее обрабатываются типом decimal : 0,1, например, можно в точности представить экземпляром decimal . При этом не существует экземпляра double или float , который точно представляет 0,1. Из-за этой разницы в числовых типах в арифметических вычислениях могут возникать непредвиденные ошибки округления при использовании double или float для десятичных данных. Вы можете использовать double вместо decimal , если оптимизация производительности важнее, чем обеспечение точности. Но любая разница в производительности останется незамеченной для всех приложений, кроме самых требовательных к вычислениям. Еще одна возможная причина, по которой следует избегать decimal , — это минимальные требования к хранилищу. Например, ML.NET использует float , так как разница между 4 байтами и 16 байтами суммируется для очень больших наборов данных. Для получения дополнительной информации см. System.Decimal.

В одном и том же выражении можно сочетать и целочисленные типы, и типы float и double . В этом случае целочисленные типы неявно преобразуются в один из типов с плавающей запятой. При необходимости тип float неявно преобразуется в double . Выражение вычисляется следующим образом.

  • Если в выражении есть тип double , оно оценивается как double или bool в реляционных сравнениях или сравнениях на равенство.
  • Если в выражении нет типа double , оно оценивается как float или bool в реляционных сравнениях или сравнениях на равенство.

Можно также смешивать целочисленные типы и тип decimal в выражении. В этом случае целочисленные типы неявно преобразуются в тип decimal , а выражение вычисляется как decimal или bool в реляционных сравнениях и сравнениях на равенство.

Тип decimal нельзя смешивать с типами float и double в выражении. В этом случае, если требуется выполнить арифметические операции или операции сравнения или равенства, необходимо явно преобразовать операнды из типа или в тип decimal , как показано в следующем примере:

double a = 1.0; decimal b = 2.1m; Console.WriteLine(a + (double)b); Console.WriteLine((decimal)a + b); 

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

Вещественные литералы

Тип реального литерала определяется его суффиксом следующим образом:

  • Литерал без суффикса или с суффиксом d или D имеет тип double .
  • Литерал с суффиксом f или F имеет тип float .
  • Литерал с суффиксом m или M имеет тип decimal .

В приведенном ниже коде показан пример каждого из них.

double d = 3D; d = 4d; d = 3.934_001; float f = 3_000.5F; f = 5.4f; decimal myMoney = 3_000.5m; myMoney = 400.75M; 

В предыдущем примере также показано использование _ в качестве разделителя цифр. Цифровой разделитель можно использовать со всеми видами числовых литералов.

Можно также использовать экспоненциальное представление, то есть указать экспоненту вещественного литерала, как показано в следующем примере:

double d = 0.42e2; Console.WriteLine(d); // output 42 float f = 134.45E-2f; Console.WriteLine(f); // output: 1.3445 decimal m = 1.5E6m; Console.WriteLine(m); // output: 1500000 

Преобразования

Существует только одно неявное преобразование между числовыми типами с плавающей запятой: из float в double . Однако можно преобразовать любой тип с плавающей запятой в любой другой тип с плавающей запятой с помощьюявного приведения. Для получения дополнительной информации см. статью Встроенные числовые преобразования.

Спецификация языка C#

Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:

  • Типы с плавающей запятой
  • Тип decimal
  • Вещественные литералы

См. также

  • справочник по C#
  • Типы значений
  • Целочисленные типы
  • Строки стандартных числовых форматов
  • Числовые значения в .NET
  • System.Numerics.Complex

Совместная работа с нами на GitHub

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

Можно ли сравнивать float с нулем?

Все мы знаем, что к float нельзя (точнее не рекомендуется) применять операцию == . Почему — думаю сами знаете. Но что насчет сравнения с 0? То есть, допустим, у нас есть какая-то переменная, проинициализированная нулем при создание, а далее, возможно, что ей будет присвоено какое-то значение, а может и не будет. Соответственно, если значение переменной равно нулю — то она не была проинициализирована. Так как при инициализации нулем все биты в переменной будут выставлены в 0, то я не вижу причин почему бы не сравнивать float (в данном случае) с нулем. Так ли это?

Отслеживать
13.7k 12 12 золотых знаков 43 43 серебряных знака 75 75 бронзовых знаков
задан 6 ноя 2018 в 16:21
Andrej Levkovitch Andrej Levkovitch
8,047 2 2 золотых знака 19 19 серебряных знаков 46 46 бронзовых знаков

По большому счету, применять сравнение на равенство с инициализатором (было изменено значение или нет) можно для любого значения, лишь бы сам инициализатор выглядел точно так же 🙂 — в том смысле, что битовое представление будет одинаковым.

6 ноя 2018 в 16:26

Тогда уж Nan какой-нибудь использовать, а не 0 . Или вовсе std::optional , если нужно отличать наличие значения.

7 ноя 2018 в 15:21

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Если известно, что число представлено точно, а именно:

  1. Нет никакой вычислительной погрешности
  2. Константа сама представима в соответствующем типе без погрешности

то сравнивать на равенство можно.

В остальных случаях сравнение нежелательно и может привести к неправильному результату.

Отслеживать
ответ дан 6 ноя 2018 в 16:55
123k 24 24 золотых знака 126 126 серебряных знаков 303 303 бронзовых знака

Не рекомендуется сравнивать вычисленный float на равенство с нулем.

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

Предположим есть код.

float n=0; float a1; float a2; //здесь a1 и a2 получили какие-то значения, //возможно пришедшие из внешнего мира (например считанные с АЦП) float delta=a1-a2; if(delta==n) < //do something1 >else < //do something2 >

Когда вычисляется разность delta a1 и a2 могут быть равны с точностью до точности типа float.
Но разность будет не равна нулю и соответственно, сравнение на равенство нулю не пройдет.
И алгоритм пойдет по другой ветке.

В качестве delta может быть не простая разность, а сколь угодно сложные вычисления.
В которых будут и ошибки округления, которые дадут +-1 к точности float.

Поэтому не рекомендуется.

Для двух констант, конечно, это будет работать.
Причем и для ненулевых констант тоже будет работать (на одной и той же платформе конечно).

float n1=0; float n2=0; if(n1==n2) < //do something1 >else < //do something2 >

Или пример для ненулевых констант:

float n1=1.1; float n2=1.1; if(n1==n2) < //do something1 >else < //do something2 >

Но в общем случае, когда float получен после вычислений, на конце у float будет +-1 точности float.
А может и больше, чем +-1 точности float.

И что такое «+-1 точности float» — это какой-то необщепринятый термин

Что-то я не помню, какой для этого есть общепринятый термин.
Может быть «машинный эпсилон» это термин для этого, то есть константа FLT_EPSILON из float.h.
А может быть FLT_MIN это термин для этого.
Наверное все-таки FLT_EPSILON.

Возможная подпрограмма сравнения на равенство для float (если сделать из нее шаблон, то подойдет и для других форматов с плавающей точкой):

bool compare_fl_point(float a1, float a2, float delta=FLT_EPSILON)< float delta1=a1-a2; if(delta1<0) delta1=-delta1; if(delta1>delta) return false; else return true; > 

В качестве параметра delta надо выбирать точность вычислений в данной задаче с учетом точности исходных данных и точности собственно вычислений на данной платформе.
Обычно рекомендуется, чтобы точность собственно вычислений на данной платформе превосходила точность входных данных как минимум на порядок.

EPSILON работает несколько иначе – Kromster 1 час назад

Эпсилон здесь только для примера в качестве дефолтного значения.
Более того, сравнивать с эпсилоном бессмысленно, так как эпсилон (по определению) всегда меньше или равен любому float числу.
На месте эпсилона должна быть точность входных данных в данной конкретной задаче.
Обычно точность вычислений выбирают так, чтобы она была как минимум в 10 раз выше, чем точность входных данных.

А вообще-то нужно погуглить этот вопрос.
Тут двух мнений быть не может, есть правила, написанные разработчиками стандарта на float.
Там однозначно говорится, как надо сравнивать float на равенство.
Я погуглил, но сходу выпало только такие же безответственные базары разработчиков на форумах, как и здесь.
Должен быть стандарт, в котором все это прописано.
Можно еще попробовать у Кнута посмотреть, может быть у него есть.

А вот, нашел что-то похожее на статью по теме:

Там есть и про сравнение float на равенство.
И даже отсылка к какой-то импортной статье.

Решил провести вычислительный эксперимент, чтобы посмотреть, как появляются ошибки округления float.
Для этого написал программу, проверяющую известное тождество sin(x)^2+cos(x)^2=1;

Как сравнить тип данных double/float в условии?

Пишу:
if($arr[‘P’] == 0.5)
не работает. не попадает в выборку данный массив. как правильно сравнивать подобный тип данных и с чем может быть связана проблема?

UPD:
Как оказалось, проблема не в этом, а в невозможности сравнивать сразу 3 условия, если сравниваю любые другие два, то все работает. Не понимаю, в чем дело.

  • Вопрос задан более трёх лет назад
  • 5672 просмотра

Комментировать
Решения вопроса 1
gelirgwenn @gelirgwenn

Вы некорректно сравниваете числа типа float. Все числа хранятся в двоичном представлении на компьютере, так уж заведено, выбрана такая система счисления, потому что информацию в виде нулей и единиц легче обрабатывать и легче делать чипы и т.п.
Так вот некоторые числа не имеют точного представления в двоичной системе. Например, 0,2 имеет вид примерно такой 0,2000000033. Соответственно, при сравнении в лоб, вы не сможете гарантировать корректный результат. Вы можете, к примеру, пробовать сравнивать сравнивать разницу с допустимой абсолютной погрешностью:

if (abs($x – $y) < 0.0001) < // Do something. >

Недостаток данного метода описан здесь, а также другие способы сравнения.
Я бы вам рекомендовал перевести float в целое число или строку. В первом случае вы будете сравнивать два целых числа и у вас не будет проблем, во втором — с помощью функции number_format и заданной точности вы преобразуете число в строку, а далее можете сравнивать строки, содержащие числа, с помощью функции bccomp или аналога:

$x = 0.200000000646456546; $y = 0.200000000676790909; $results = ($x == $y); var_dump($results); // bool(false) $results = bccomp(number_format($x, 5), number_format($y, 5)); var_dump($results); // int(0) - are equal

Как сравнить float с 0

Привет всем!
Есть два числа типа float,
одно содержит 0.50000002607703
другое — 0.50000000000000
Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

Take it easy.
Re: Сравнение float

От: Kaa http://blog.meta.ua/users/kaa/
Дата: 19.02.02 16:24
Оценка:

Здравствуйте Yuri, Вы писали:

Y>Привет всем!
Y>Есть два числа типа float,
Y>одно содержит 0.50000002607703
Y>другое — 0.50000000000000
Y>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

Первое, что приходит в голову — умножить на 100 (на 10 в степени кол-ва нуждных тебе разрядов, в этом случае — 2). и отбросить дробную часть, и сравнить. Или, после умножения вычесть меньшее из большего, и сравнить разность. Если она меньше единицы — все хорошо, это оно.

Алексей Кирдин
Re[2]: Сравнение float

От: Sergey
Дата: 19.02.02 16:36
Оценка:

Здравствуйте Kaa, Вы писали:

Kaa>Здравствуйте Yuri, Вы писали:

Y>>Привет всем!
Y>>Есть два числа типа float,
Y>>одно содержит 0.50000002607703
Y>>другое — 0.50000000000000
Y>>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

Kaa>Первое, что приходит в голову — умножить на 100 (на 10 в степени кол-ва нуждных тебе разрядов, в этом случае — 2). и отбросить дробную часть, и сравнить.
Так делать нельзя. Например, сравни 2.9999999999 и 3.000000000

Kaa>Или, после умножения вычесть меньшее из большего, и сравнить разность. Если она меньше единицы — все хорошо, это оно.

А вот это уже правильно, только умножать незачем — вычесть, сравнить с допустимой ошибкой.

Одним из 33 полных кавалеров ордена «За заслуги перед Отечеством» является Геннадий Хазанов.
Re: Сравнение float

От: Кодт
Дата: 19.02.02 16:36
Оценка:

Здравствуйте Yuri, Вы писали:

Y>Привет всем!
Y>Есть два числа типа float,
Y>одно содержит 0.50000002607703
Y>другое — 0.50000000000000
Y>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

1) округление до 0.01

inline double round_to(double value, double eps) < assert(eps >0); return floor(value/eps + 0.5) * eps; > inline int compare_1(double a, double b, double eps) < double diff = floor(a/eps + 0.5) - floor(b/eps + 0.5); return diff < 0 ? -1 : diff >0 ? +1 : 0; > compare_1(0.5123, 0.5145, 0.01); diff = floor(51.23 + 0.5) - floor(51.45 + 0.5) == 51-51 = 0

2) числа в окрестности +/- 1% считать равными

inline double compare_2(double a, double b, double eps) < double diff = round_to( (a - b) * 2 / (a + b), eps); return diff < 0 ? -1 : diff >0 ? +1 : 0; > compare_2(0.000512, 0.000534, 0.01) diff = round_to( -0.000022 / 0.000522, 0.01 ) = round_to( -0.0421. 0.01 ) = -0.04 compare_2(0.0005123, 0.0005145, 0.01) diff = round_to( -0.0000022 / 0.0005122, 0.01 ) = round_to( -0.00429. 0.01 ) = 0

Перекуём баги на фичи!
Re[3]: Сравнение float

От: Kaa http://blog.meta.ua/users/kaa/
Дата: 19.02.02 16:42
Оценка:

Здравствуйте Sergey, Вы писали:

Чего к словам придираться. Все всё поняли. Дело в алгоритме.

Kaa>>Первое, что приходит в голову — умножить на 100 (на 10 в степени кол-ва нуждных тебе разрядов, в этом случае — 2). и отбросить дробную часть, и сравнить.
S> Так делать нельзя. Например, сравни 2.9999999999 и 3.000000000
299.0 != 300.0, что и требовалось доказать. Что не так? В чем «нельзя»?

Kaa>>Или, после умножения вычесть меньшее из большего, и сравнить разность. Если она меньше единицы — все хорошо, это оно.

S> А вот это уже правильно, только умножать незачем — вычесть, сравнить с допустимой ошибкой.

Можно и не умножать. Тогда погрешность (допустимую ошибку) знать надо.

Алексей Кирдин
Re[4]: Сравнение float

От: Sergey
Дата: 19.02.02 16:54
Оценка:

Здравствуйте Kaa, Вы писали:

Kaa>Здравствуйте Sergey, Вы писали:

Kaa>Чего к словам придираться. Все всё поняли. Дело в алгоритме.

Kaa>>>Первое, что приходит в голову — умножить на 100 (на 10 в степени кол-ва нуждных тебе разрядов, в этом случае — 2). и отбросить дробную часть, и сравнить.
S>> Так делать нельзя. Например, сравни 2.9999999999 и 3.000000000
Kaa>299.0 != 300.0, что и требовалось доказать. Что не так? В чем «нельзя»?

Ты всерьез полагаешь, что человеку надо именно это — два числа, отличающиещиеся на 0.0е-10, считать разными? Если да, то можно просто битмаской лишнее прихлопнуть (сколько там двоичных знаков, сразу и не соображу) и сравнивать — будет типа очень быстро

Kaa>>>Или, после умножения вычесть меньшее из большего, и сравнить разность. Если она меньше единицы — все хорошо, это оно.

S>> А вот это уже правильно, только умножать незачем — вычесть, сравнить с допустимой ошибкой.

Kaa>Можно и не умножать. Тогда погрешность (допустимую ошибку) знать надо.

Kaa>С уважением

Одним из 33 полных кавалеров ордена «За заслуги перед Отечеством» является Геннадий Хазанов.
Re: Сравнение float

От: Курилка http://kirya.narod.ru/
Дата: 19.02.02 17:04
Оценка: +1

Здравствуйте Yuri, Вы писали:

Y>Привет всем!
Y>Есть два числа типа float,
Y>одно содержит 0.50000002607703
Y>другое — 0.50000000000000
Y>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

Re[5]: Сравнение float

От: Kaa http://blog.meta.ua/users/kaa/
Дата: 19.02.02 17:11
Оценка:

Здравствуйте Sergey, Вы писали:

S> Ты всерьез полагаешь, что человеку надо именно это — два числа, отличающиещиеся на 0.0е-10, считать разными? Если да, то можно просто битмаской лишнее прихлопнуть (сколько там двоичных знаков, сразу и не соображу) и сравнивать — будет типа очень быстро
Вопрос перечитай, что-ли. Ему надо, в твоих терминах, отождествить 2 числа с одинаковыми первыми тремя разрядами при равным показателем степени в стандартной заприси числа.

Алексей Кирдин
Re[6]: Сравнение float

От: Sergey
Дата: 20.02.02 08:04
Оценка:

Здравствуйте Kaa, Вы писали:

Kaa>Здравствуйте Sergey, Вы писали:

S>> Ты всерьез полагаешь, что человеку надо именно это — два числа, отличающиещиеся на 0.0е-10, считать разными? Если да, то можно просто битмаской лишнее прихлопнуть (сколько там двоичных знаков, сразу и не соображу) и сравнивать — будет типа очень быстро
Kaa>Вопрос перечитай, что-ли. Ему надо, в твоих терминах, отождествить 2 числа с одинаковыми первыми тремя разрядами при равным показателем степени в стандартной заприси числа.

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

Одним из 33 полных кавалеров ордена «За заслуги перед Отечеством» является Геннадий Хазанов.
Re[2]: Сравнение float

От: Kaa http://blog.meta.ua/users/kaa/
Дата: 20.02.02 13:18
Оценка:

Здравствуйте Курилка, Вы писали:

К>Здравствуйте Yuri, Вы писали:

Y>>Привет всем!
Y>>Есть два числа типа float,
Y>>одно содержит 0.50000002607703
Y>>другое — 0.50000000000000
Y>>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

К>я дак делаю fabs(val1-val2) К>где delta — необходимая точность

Это немного не то. Вот тебе пример:
2.99092 -> 2.99 != 3.00 -> 3.00, хотя при этом |2.99092 — 3.00| < 0.01
Короче говоря, требуется совпадение разрядов, а не просто их близость на числовой прямой.

Алексей Кирдин
Re[3]: Сравнение float

От: Курилка http://kirya.narod.ru/
Дата: 20.02.02 13:38
Оценка:

Здравствуйте Kaa, Вы писали:

Kaa>Здравствуйте Курилка, Вы писали:

К>>Здравствуйте Yuri, Вы писали:

Y>>>Привет всем!
Y>>>Есть два числа типа float,
Y>>>одно содержит 0.50000002607703
Y>>>другое — 0.50000000000000
Y>>>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

К>>я дак делаю fabs(val1-val2) К>>где delta — необходимая точность

Kaa>Это немного не то. Вот тебе пример:
Kaa>2.99092 -> 2.99 != 3.00 -> 3.00, хотя при этом |2.99092 — 3.00| < 0.01
Kaa>Короче говоря, требуется совпадение разрядов, а не просто их близость на числовой прямой.

И кому такое сравнение нужно. Стесняюсь спросить.

тогда и 2.9901 будет равно 3.0099?
по-моему для нормальной задачи это бред

Re[4]: Сравнение float

От: Kaa http://blog.meta.ua/users/kaa/
Дата: 20.02.02 13:45
Оценка: 1 (1)

Здравствуйте Курилка, Вы писали:

Y>>>>Привет всем!
Y>>>>Есть два числа типа float,
Y>>>>одно содержит 0.50000002607703
Y>>>>другое — 0.50000000000000
Y>>>>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой
Это видел?

Kaa>>Это немного не то. Вот тебе пример:
Kaa>>2.99092 -> 2.99 != 3.00 -> 3.00, хотя при этом |2.99092 — 3.00| < 0.01
Kaa>>Короче говоря, требуется совпадение разрядов, а не просто их близость на числовой прямой.

К>И кому такое сравнение нужно. Стесняюсь спросить.
Ему нужно, спрашивающему.

К>тогда и 2.9901 будет равно 3.0099?
Когда — «тогда». Отождествляются только чиса с первыми тремя разрядами. В твоем примере это не так. Разряды различаются. Так, напимер, можно сравнивать деньги: целые — рубли, дробные — копейки. Без большой точности. Это, ты считаешь, не реальная задача? )

Алексей Кирдин
Re[5]: Сравнение float

От: Курилка http://kirya.narod.ru/
Дата: 20.02.02 13:51
Оценка:

Здравствуйте Kaa, Вы писали:
К>>тогда и 2.9901 будет равно 3.0099?
Kaa>Когда — «тогда». Отождествляются только чиса с первыми тремя разрядами. В твоем примере это не так. Разряды различаются.

сорри, я имел в виду 2.9999 != 3.00
вечно пишу совсем не то, что думаю

Kaa>Так, напимер, можно сравнивать деньги: целые — рубли, дробные — копейки. Без большой точности. Это, ты считаешь, не реальная задача? )

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

Re[6]: Сравнение float

От: Кодт
Дата: 21.02.02 10:16
Оценка:

Здравствуйте Курилка, Вы писали:

К>Здравствуйте Kaa, Вы писали:
К>>>тогда и 2.9901 будет равно 3.0099?
Kaa>>Когда — «тогда». Отождествляются только чиса с первыми тремя разрядами. В твоем примере это не так. Разряды различаются.

К>сорри, я имел в виду 2.9999 != 3.00
К>вечно пишу совсем не то, что думаю

Kaa>>Так, напимер, можно сравнивать деньги: целые — рубли, дробные — копейки. Без большой точности. Это, ты считаешь, не реальная задача? )

К>наверно ты прав, хотя на мой взгляд это тоже спорно, как деньги округлять.

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

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