Вычисления с плавающей запятой что это

Представление чисел с плавающей точкой

Содержание

Плавающая точка [ править ]

Такой метод является компромиссом между точностью и диапазоном представляемых значений. Представление чисел с плавающей точкой рассмотрим на примере чисел двойной точности (double precision). Такие числа занимают в памяти два машинных слова (8 байт на 32-битных системах). Наиболее распространенное представление описано в стандарте IEEE 754.

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

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

Нормальная и нормализованная формы [ править ]

Числа двойной точности [ править ]

Число с плавающей точкой хранится в нормализованной форме и состоит из трех частей (в скобках указано количество бит, отводимых на каждую секцию в формате double):

Знак
Экспонента
(11 бит)
Мантисса
(52+1 бит)
0000000000001,0000000000000000000000000000000000000000000000000000
6252510

Свойства чисел с плавающей точкой [ править ]

Особые значения чисел с плавающей точкой [ править ]

Ноль (со знаком) [ править ]

В нормализованной форме невозможно представить ноль. Для его представления в стандарте зарезервированы специальные значения мантиссы и экспоненты.

Утверждение:
Знак
ЭкспонентаМантисса
0 /1000001,0000000000= [math]\pm0[/math]

Согласно стандарту выполняются следующие свойства:

Бесконечность (со знаком) [ править ]

Для приближения ответа к правильному при переполнении, в double можно записать бесконечное значение. Так же, как и в случае с нолем, для этого используются специальные значение мантиссы и экспоненты.

Знак
ЭкспонентаМантисса
0 /1111111,0000000000= [math]\pm\infty[/math]

Бесконечное значение можно получить при переполнении или при делении ненулевого числа на ноль.

Неопределенность [ править ]

В математике встречается понятие неопределенности. В стандарте double предусмотрено псевдочисло, которое арифметическая операция может вернуть даже в случае ошибки.

Знак
ЭкспонентаМантисса
0 /1111111,0 /10 /10 /10 /10 /10 /10 /10 /10 /10 /1= [math]NaN[/math]

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

Денормализованные числа [ править ]

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

Начиная с версии стандарта IEEE 754 2008 года денормализованные числа называются «субнормальными» (subnormal numbers), то есть числа, меньшие «нормальных».

Машинная эпсилон [ править ]

Unit in the last place (Unit of least precision) [ править ]

Мера единичной точности используется для оценки точности вычислений.

Погрешность предиката «левый поворот» [ править ]

Определения [ править ]

[math] \exists \tilde <\epsilon>\in D: [/math]

Расчет [math] \tilde <\epsilon>[/math] [ править ]

Теперь распишем это выражение в дабловой арифметике.

[math] |\delta_i| \leq \varepsilon_m [/math]

Заметим, что [math] v \approx \tilde [/math]

Ответ [ править ]

[math] \tilde <\epsilon>\lt 8 \varepsilon_m \tilde[/math]

Заметим, что это довольно грубая оценка. Вполне можно было бы написать [math] \tilde <\epsilon>\lt 4.25 \varepsilon_m \tilde[/math] или [math] \tilde <\epsilon>\lt 4.5 \varepsilon_m \tilde.[/math]

Источник

Числа с плавающей запятой

Кувшинов Д.Р.

IEEE-754

Введение

Для работы с вещественными числами могут использоваться различные способы покрытия вещественной оси (конечным) набором представимых чисел. Как правило, они ограничиваются определенным подмножеством рациональных чисел:

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

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

Наиболее распространенным стандартом представления и правил работы с числами с плавающей запятой является стандарт IEEE-754 (в последней редакции известный также под обозначением ISO/IEC/IEEE 60559:2011). Его поддерживают большинство современных процессоров, умеющих работать с числами с плавающей запятой “непосредственно”.

Формат

IEEE-754 задаёт следующее двоичное представление числа.

Двоичное представление числа с плавающей запятой

Знак sЭкспонента EМантисса M
1 разрядe разрядовm разрядов
старший битбиты (m + e – 1) … mбиты (m – 1) … 0

Экспонента exponent — обычно то же, что и порядок, однако в конкретных форматах порядок (как целое число) закодирован специальным образом (не равен численно беззнаковому представлению E), см. ниже.

В таблице ниже приведены сведения о четырёх основных двоичных (т.е. r = 2) форматах стандарта IEEE-754. Число ε — наименьшее положительное представимое число такое, что 1 + ε ≠ 1 в заданном формате. Смысл понятий “денорм.” (денормализованные числа) и “норм.” (нормализованные числа) дан ниже. В качестве числа d в таблице указано минимальное число десятичных знаков после запятой, которого достаточно для сохранения двоичного представления числа при преобразовании в десятичную форму и обратно. Необходимо помнить, что многие десятичные дроби являются бесконечными в двоичной системе: например, 0.2 не представимо точно в указанных форматах. Двоичные же дроби хотя и представимы точно конечным числом знаков, могут потребовать сотни десятичных цифр для точной записи.

Четыре стандартных формата

Формат“Точность” precisionвсего битemdεmin денорм.min норм.max норм.
binary16половинная half1651059.77·10 –45.96·10 –86.1·10 –565504
binary32одинарная single3282391.19·10 –71.4·10 –451.18·10 –383.4·10 38
binary64двойная double641152172.22·10 –164.94·10 –3242.2·10 –3081.8·10 308
binary128четверная quadruple12815112361.93·10 –346.48·10 –49663.4·10 –49321.2·10 4932

Порядок представлен в сдвинутом коде со сдвигом b = 2 e–1 – 1. Максимальное и минимальное значение E, взятого как беззнаковое число, интерпретируются особым образом.

Интерпретация представления числа с плавающей точкой, М — биты мантиссы (двоичная дробь)

Тип значенияEMЗначение числа с плав. точкой
нуль00(–1) s ·0
денормализованное0≠ 0(–1) s ·0.(M)·2 1–b
нормализованное1 … 2 bлюбое(–1) s ·1.(M)·2 Eb
бесконечность2 b + 10(–1) s ·∞
нечисло (“NaN”)2 b + 1≠ 0код ошибки

Запись 0.(M) или 1.(M) означает, что m бит мантиссы выписываются после точки в двоичной записи числа. Под нормализацией числа понимается его домножение на такую степень двойки, что слева от точки получается единица. Денормализованные числа требуют недоступных значений экспоненты для нормализации.

Замечания

Режимы округления

Стандарт IEEE-754 предусматривает наличие пяти режимов округления, которые можно проиллюстрировать с помощью следующей таблицы.

Режимы округления IEEE-754

Режим (округление к целому)–2.7–2.5–2.2–1.51.52.22.52.7
к ближайшему, половинки к чётному to nearest, ties to even–3.0–2.0–2.0–2.02.02.02.03.0
к ближайшему, половинки от нуля to nearest, away from zero–3.0–3.0–2.0–2.02.02.03.03.0
к нулю toward zero, truncation–2.0–2.0–2.0–1.01.02.02.02.0
к плюс-бесконечности to positive infinity, upwards, ceiling–2.0–2.0–2.0–1.02.03.03.03.0
к минус-бесконечности to negative infinity, downwards, floor–3.0–3.0–3.0–2.01.02.02.02.0

При округлении к ближайшему представимому выбор в пользу округления половинок именно к чётному (как правило, используется именно этот вариант, например, на x86) или нечётному вместо “школьного” округления “от нуля” был сделан с целью балансировки накапливающихся округлений и уменьшению случайной погрешности.

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

Числа с плавающей запятой в C и C++

Одна из типичных ошибок новичков — использование целочисленных констант там, где необходимы константы в плавающей точке.

В примере выше 1 и 3 — целые числа, поэтому к ним применяется целочисленное деление (с отбрасыванием остатка), т.е. 1/3 = 0. Поэтому функция bad_cubic_root не вычисляет кубический корень. Правильным вариантом будет следующий код (также с учётом знака, так как стандартная функция возведения в степень не принимает отрицательное основание и нецелый показатель)

В стандарте C++11, впрочем, определена функция для вычисления кубического корня (cbrt). При её наличии следует использовать её вместо варианта на основе pow.

Языки C и C++ предоставляют три встроенных типа для работы с числами с плавающей точкой:

Стандарт гарантирует лишь отношение float ⊆ double ⊆ long double.

Часть характеристик форматов с плавающей запятой, используемых конкретным компилятором, можно получить, подключив заголовочный файл cfloat, где определен ряд макросов. Ниже * соответствует FLT для типа float, DBL для double и LDBL для long double.

Стандартные средства управления режимом округления и реакцией на исключительные ситуации (ошибки, приводящие к появлению нечисел, переполнения и округления со значительной потерей точности) предоставлены в заголовочном файле cfenv.

Заголовочный файл cmath

Заголовочный файл cmath предоставляет ряд определений математических функций (вычисляемых приближённо в плавающей точке, тем не менее, для простоты в обозначениях используются действительные числа вплоть до всей числовой оси). Здесь приводятся сведения по определениям для C++, принимающим разнотипные значения (float, double и long double). Если предел той или иной функции при стремлении к нулю (с той или иной стороны) или бесконечностям определён (включая значения ±∞), то он берётся в качестве значения этой функции в соответствующих предельных точках (поэтому многие интервалы и полуинтервалы в колонке “область значений” могут считаться отрезками).

Тригонометрические и гиперболические функции

ФункцияОбласть определенияОбласть значенийЗамечание
sin(x)[–1, 1]x в радианах
cos(x)[–1, 1]x в радианах
tan(x)x ∉ πℤ + π/2неограниченный рост погрешности около точек разрыва
asin(x)[–1, 1][–π/2, π/2]
acos(x)[–1, 1][0, π]
atan(x)[–π/2, π/2]
atan2(y, x)ℝ 2[–π, π]угол против часовой стрелки между векторами (1, 0) и (x, y)
sinh(x)
cosh(x)[1, +∞)
tanh(x)(–1, 1)
asinh(x)C++11
acosh(x)[1, +∞)C++11
atanh(x)(–1, 1)C++11

Степени и логарифмы

ФункцияОбласть определенияОбласть значенийЗамечание
exp(x)(0, +∞)константа Эйлера e (основание натурального логарифма) в степени x
expm1(x)(–1, +∞)C++11, формально то же, что exp(x) – 1, но сохраняет высокую точность при x ≈ 0
exp2(x)(0, +∞)C++11, 2 x
log(x)(0, +∞)натуральный логарифм
log10(x)(0, +∞)десятичный логарифм
log1p(x)(–1, +∞)C++11, формально то же, что log(x + 1), но сохраняет высокую точность при x ≈ 0
log2(x)(0, +∞)C++11, двоичный логарифм
sqrt(x)[0, +∞)[0, +∞)квадратный корень
cbrt(x)C++11, кубический корень
hypot(x, y)ℝ 2[0, +∞)C++11, sqrt(x 2 + y 2 ), без промежуточного переполнения
pow(x, i)ℝ × ℤвозведение x в целочисленную степень i
pow(x, y)(0, +∞) × ℝ(0, +∞)возведение x в степень с показателем y, заданным в плавающей точке

Округление

ФункцияЗамечание
ceil(x)округление наверх: ⌈x⌉, результат в формате плавающей точки
floor(x)округление вниз: ⌊x⌋, результат в формате плавающей точки
trunc(x)C++11, округление к нулю, результат в формате плавающей точки
round(x)C++11, округление к ближайшему целому (режим “от нуля” для половинок), результат в формате плавающей точки
lround(x)C++11, округление к ближайшему целому, результат в формате long int
llround(x)C++11, округление к ближайшему целому, результат в формате long long int
nearbyint(x)C++11, округляет до целых, используя текущий режим округления (который можно выставить с помощью fesetround)

При использовании C или для явного указания того, что аргумент и результат функции “абсолютное значение” имеют тип double, следует использовать функцию fabs вместо abs. См. также о целочисленном варианте abs.

Управление режимом округления cfenv

Подключив заголовочный файл cfenv можно управлять текущим режимом округления. Возможен выбор из четырёх стандартных (по стандарту C) режимов:

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

Точность операций

Абсолютная погрешность x равна |xx * |.

Относительная погрешность x при условии x * ≠ 0 равна |xx * |/|x * |.

При выполнении арифметических операций, вычислении функции fma (слитое умножение-сложение fused multiply–add ), а также вычислении квадратного корня результат округляется к ближайшему представимому в текущем формате числу, т.е. имеет точность 0.5 ULP (при использовании соответствующего режима округления). Одним из следствий такого округления является точный результат sqrt от квадрата целого числа (если он представим). Вычисление тригонометрических функций, степеней и логарифмов обычно выполняется не столь точно, давая погрешность в 1–5 ULP и более (зависит от реализации). В результате вычисление формул, содержащих такие функции, с одними и теми же значениями переменных может давать разные результаты на разных платформах.

Благодаря двоичному формату чисел IEEE-754, при интерпретации их как целых (на некоторых платформах может потребоваться обращение порядка байт), модуль их разности в случае совпадения знака и порядка равен расстоянию между ними в ULP.

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

В качестве eps можно брать кратное DBL_EPSILON — оценивать разность в “эпсилонах”.

Наконец, можно оценивать погрешность непосредственно в ULP.

В отличие от предыдущих вариантов, ulp_equal вернет true для бесконечностей одного знака. В то же время расстояние в ULP от DBL_MAX до +∞ равно всего лишь единице. Нечисла также могут оказаться “почти равными”. Напротив, расстояние между –0 и +0 получается очень большим (числа разного знака таким способом сравнивать в общем-то бессмысленно, и определённая ниже функция возвращает ложь для неравных чисел разного знака).

Функция memcpy копирует кусок памяти.

Продолжая тему оперирования непосредственно двоичными представлениями чисел с плавающей запятой формата IEEE-754, можно обратить внимание на следующее. Предположим, что a ≥ +0 (поведение отрицательных чисел аналогично), тогда при увеличении a, интерпретируемого как целое, на единицу получаем:

Простым циклом можно перечислить все представимые неотрицательные числа с плавающей точкой формата binary32:

Стандартным средством получения следующего представимого числа является функция nextafter (см. в таблице, приведённой в разделе, описывающем стандартный заголовочный файл cmath):

Примеры

Параметр линейной интерполяции

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

Lerp — распространённая аббревиатура английского linear interpolation — “линейная интерполяция”.

Однако округление при вычитании существенно различных по величине t1 и h может приводить к выходу конечного результата за пределы отрезка [0, 1]. Исправленный вариант может выглядеть так:

Вычисление значений многочленов

Метод Горнера

Воспользовавшись стандартной функцией fma можно попробовать увеличить точность функции poly_horner (сократив половину промежуточных округлений).

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

Метод Эстрина

Впрочем, можно попробовать ещё ускорить данную операцию, если у нас в распоряжении имеется процессор, способный исполнять одновременно более одной команды (в данном случае имеется в виду не “многоядерность”, а наличие таких аппаратных особенностей как глубокий конвейер и/или суперскалярность и/или SIMD-команды). Для этого воспользуемся ассоциативностью суммы (впрочем, в плавающей точке ассоциативность теряется, поэтому результат может не совпадать с результатом функции poly_horner_fma). Кроме того, чтобы игра стоила свеч, нужен многочлен высокой степени (с большим количеством членов).

Один шаг: разбить по квадратам x.

Второй шаг: разбить по квадратам квадратов x.

Вычисления с плавающей запятой что это. Смотреть фото Вычисления с плавающей запятой что это. Смотреть картинку Вычисления с плавающей запятой что это. Картинка про Вычисления с плавающей запятой что это. Фото Вычисления с плавающей запятой что этоОбобщение метода Горнера — метод Эстрина: дерево суммирования по квадратам

Вычисление произведения последовательности без промежуточного переполнения или исчезновения

Иногда случается ситуация, когда требуется вычислить произведение элементов некоторой конечной последовательности чисел в плавающей точке, хранящихся в массиве, читаемых с потока или вычисляемых по формуле. Так или иначе, в процессе такого вычисления может возникнуть неприятная ситуация: нехватка диапазона экспоненты для представления величины промежуточного результата, в то время как правильно вычисленных конечный результат представим. Например, для простоты представим себе последовательность, состоящую из двух тысяч двоек и двух тысяч “половинок” (0.5). Произведение равно единице. Однако, даже при использовании формата binary64 ещё на первой половине произойдёт переполнение, так как 2 2000 слишком велико, и общий результат наивного последовательного перемножения получится равным бесконечности. Если перемножать с конца к началу, то произойдёт исчезновение, так как 2 –2000 слишком мало, и общий результат получится равным нулю.

Суммирование с компенсацией погрешности округлений

Алгоритм, называемый суммированием Кэхэна или компенсационным суммированием (У.Кэхэн), позволяет получить гораздо более точный результат, суммируя отброшенные при округлении основной суммы части в отдельной переменной — компенсации (в примере реализации — переменная comp ). Относительная погрешность этого алгоритма ограничена сверху значением (цитир. по: Higham N. The accuracy of floating point summation // SIAM J. Sci. Comput. 1993. Vol. 14, No. 4. P.783–799)

Вычисления с плавающей запятой что это. Смотреть фото Вычисления с плавающей запятой что это. Смотреть картинку Вычисления с плавающей запятой что это. Картинка про Вычисления с плавающей запятой что это. Фото Вычисления с плавающей запятой что этоПогрешность компенсационного суммирования

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

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

Численное решение уравнений

Пусть дана непрерывная функция f : ℝ → ℝ и два числа a 2 – 2, a = 0, b = 2.

В указанном примере на каждом шаге, очевидно, истинно m ∈ ℚ, в то же время, решения уравнения f(x) = 0 не принадлежат ℚ. Таким образом, наш алгоритм за n шагов может гарантировать лишь сужение исходного интервала, содержащего корень, в 2 n раз, но не обнаружение точного значения корня уравнения. Если достаточно знать корень с погрешностью ε > 0, то достаточно выполнить n = ⌈log2((ba)/ε)⌉ шагов.

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

Однако, при использовании физических компьютеров, абсолютно точная арифметика недоступна. При использовании чисел с плавающей запятой через конечное число шагов алгоритма станет истинно (a = m)∨(b = m) (почему?). Поэтому бисекцию можно записать следующим образом:

Вилочный метод секущих

Рассмотрим ещё другой алгоритм — вилочный метод секущих (другое название: метод ложного положения regula falsi method ), напоминающий метод бисекции в том плане, что по мере приближения корень всегда остаётся в некотором интервале. Всё отличие от предыдущего алгоритма будет состоять в способе вычисления очередной точки m. Вместо того, чтобы брать середину текущего отрезка, возьмём точку пересечения оси абсцисс секущей — прямой, проведённой через координаты (a, f(a)) и (b, f(b)). Делая так, мы “надеемся”, что на интервале [a, b] функция достаточно похожа на прямую. Это действительно так, если интервал достаточно мал, а функция f дифференцируема на нём.

Вычисления с плавающей запятой что это. Смотреть фото Вычисления с плавающей запятой что это. Смотреть картинку Вычисления с плавающей запятой что это. Картинка про Вычисления с плавающей запятой что это. Фото Вычисления с плавающей запятой что этоШаг 1: m = 30/13 ≈ 2.3077 Вычисления с плавающей запятой что это. Смотреть фото Вычисления с плавающей запятой что это. Смотреть картинку Вычисления с плавающей запятой что это. Картинка про Вычисления с плавающей запятой что это. Фото Вычисления с плавающей запятой что этоШаг 2: m = 1028/399 ≈ 2.57644 Вычисления с плавающей запятой что это. Смотреть фото Вычисления с плавающей запятой что это. Смотреть картинку Вычисления с плавающей запятой что это. Картинка про Вычисления с плавающей запятой что это. Фото Вычисления с плавающей запятой что этоШаг 3: m ≈ 2.61485 Вычисления с плавающей запятой что это. Смотреть фото Вычисления с плавающей запятой что это. Смотреть картинку Вычисления с плавающей запятой что это. Картинка про Вычисления с плавающей запятой что это. Фото Вычисления с плавающей запятой что этоШаг 4: m ≈ 2.61996

первые шаги метода секущих (значения с индексом b — результат бисекции для сравнения)

Шагmbmf(m)mbf(mb)
12.307690.692308–0.3172512–0.(5)
22.576440.423559–0.04985882.5–0.131944
32.614850.385152–0.006731582.750.155382
42.619960.380036–0.0008895642.6250.00488281
52.6206390.379361–0.0001172192.5625–0.0651991
62.6207280.379272–0.00001544042.59375–0.0305803

Легко заметить, что, с одной стороны, метод секущих уже не гарантирует нам сколь угодно малый интервал — в нашем примере бесконечное число шагов даст a = m = корень ≈ 2.62074, в то время как b так и останется в точке 3. С другой стороны, m намного быстрее подходит к корню, чем в методе бисекции.

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

Поиск минимума функции

Функция унимодальна на отрезке [a, b], если существует m ∈ [a, b] такая, что функция строго убывает на [a, m] и строго возрастает на [m, b]. Таким образом, функция достигает единственного на [a, b] минимума в точке m.

Рассмотрим задачу поиска минимума унимодальной на заданном отрезке [a, b] функции f : ℝ → ℝ.

Троичный поиск

Троичный поиск ternary search — простейший метод, решающий с заданной точностью ε поставленную задачу. Принцип его работы можно описать следующим алгоритмом:

Легко заметить, что приближение минимума (для данного примера min = –0.230445) происходит немонотонно.

Метод золотого сечения

Существует метод, основанный на том же принципе, что и троичный поиск, но более экономный — позволяющий вычислять одно новое значение функции на каждом шаге, а не два, как троичный поиск. Это метод носит название метод золотого сечения. Сократить вычисления можно в том случае, если одна из предыдущих позиций, выбранных в [a, b] будет сохраняться на каждом шаге. Этого можно добиться, если делить отрезок не на трети, а в отношении 1:φ, где φ — “золотое сечение”. Для любых x > y > 0 таких, что φ = x/y, выполняется также (x + y)/x = x/y = φ. Отсюда легко получить тождество φ = 1 + 1/φ, позволяющее вычислить φ (положительный корень квадратного уравнения).

Теперь передвинем точку b в точку d и пересчитаем новые c‘и d’:

Итак, алгоритм можно записать следующим образом:

Источник

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

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