float в теории и на практике


Содержание

Детали плавающей точки (5 стр)

Программная поддержка

В основном рассматривается поддержка чисел с плавающей точкой в языках C/C++.

Можно упомянуть, что в 2006 г. Уильям Кэхен отмечал, что

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

Стандарты C и C++

Стандарты C и C++ не требуют, чтобы арифметика с плавающей точкой реализовала именно IEEE754.
Для соответствующей IEEE754 требования изложены в Appendix F Стандарта C (в C++ соответствующий раздел отсутствует).

В C для проверки поддержки IEEE754 предназначено макро
__STDC_IEC_559__
определённое только если арифметика с плавающей точкой реализует IEEE754.
В C++ для типа type значение константы
std::numeric_limits ::is_iec559
определяет, соответствует ли данный тип IEEE754.

На практике однако данные определения проблематичны.
Компиляторы могут не определять __STDC_IEC_559__, или определять без полного соответствия стандарту.

Соответствие между C и IEEE754

Appendix F стандарта C подробно излагает соответствие между операциями IEEE754 и конструкциями (и функциями) языка C.
Подробнее см. в разделе F.3.

Компиляторы

В основном рассматриваются компиляторы GCC и Visual Studio; в меньшей степени — Clang и ICC.

Стоит отметить, что т. к. компилятор Visual Studio не поддерживает тип double-extended (см. ниже), то среда по умолчанию выставляет точность FPU в double, таким образом регистры FPU имеют точность double но диапазон double-extended. Также DirectX имеет тенденцию выставлять точность в float.

Яыки C/C++ предоставляют (согласно стандарту я) 3 типа с плавающей точкой: float, double и long double.

Типы float и double, практически всюду соответствуют binary32 и binary64 стандарта IEEE-754.

long double менее однозначен. Для x86/x86_64 в GCC и Clang он по-умолчанию соответствует 80-битному расширенному формату Intel x87. Для Visual Studio и ICC — он физически соответствует тому же типу, что и double (хотя логически (с т. з. Стандарта) является самостоятельным типом, в частности по double и long double возможна перегрузка функций). Для ICC на Windows можно воспользоваться флагом /Qlong-double, который меняет long double на 80-битный x87 (тип занимает 16 байт из соображений выравнивания). Для Visual Studio подобная возможность отсутствует — поддержка 80-битного расширенного типа x87 в ней отсутствует начиная с 32-битных версий (она присутствовала в 16-битных).

Размер типа long double (в смысле значения sizeof(long double)) для 80-битного типа x87 типично не равен 10 байтам, из соображений выравнивания: реальные значения обычно равны 12 или 16 байт. Для GCC значение можно изменить флагами компиляции -malign-double, -mno-align-double, -m96bit-long-double, -m128bit-long-double. Не используемые байты могут иметь произвольные значения.

На некоторых платформах long double означает binary128, либо использует пару 64-битных вещественных чисел, для достижения 106-битной точности, но с диапазоном обычного double (этот подход называется double-double, подробнее см. в разделе Алгоритм суммирования Кэхена).

На многих платформах (в частности x86/x86_64) GCC по умолчанию поддерживает (предоставляет в качестве расширения) нестандартный тип __float128 (а также __float80). Реализация этого типа (на архитектурах не поддерживающих binary128) программная и, соответственно, медленная. Суффикс ‘q’/’Q’ для литералов этого типа поддерживается для C, но не для C++. Пример:

На ARM GCC поддерживает binary16 (half-float) тип __fp16 в 2-х вариантах (-mfp16-format=ieee и -mfp16-format=alternative). Этот тип доступен при указании флага компиляции -mfp16-format.

Также в C, но не в C++, GCC частично поддерживает десятичные числа с плавающей точкой.

В некоторых версиях ICC есть поддержка 128-битного типа с плавающей точкой _Quad.

FLT_EVAL_METHOD

Промежуточные вычисления могут вестись в повышенной точности (это разрешено стандартом IEEE-754).
Детали описывает макро FLT_EVAL_METHOD:

Прагмы STDC (FP_CONTRACT/FENV_ACCESS/CX_LIMITED_RANGE)

Стандарт C определяет 3 прагмы относящиеся к вычислениям с плавающей точкой: FP_CONTRACT, FENV_ACCESS и CX_LIMITED_RANGE.
Все 3 прагмы могут использоваться как глобально так и на уровне блока кода.
Все 3 прагмы имеют состояния ON, OFF, DEFAULT. Состояние FP_CONTRACT FENV_ACCESS по умолчанию — implementation-defined, состояние CX_LIMITED_RANGE — OFF.
Стандарт C++ эти прагмы не определяет, но многие компиляторы в той или иной мере их поддерживают.

Данная прагма информирует компилятор о том, что программист может обращаться к окружению с плавающей точкой (floating point environment) — направлению округления и исключениям (флагам и обработчикам).
При выключенной прагме компилятор имеет право предполагать, что все действия происходят в режиме округления по умолчанию (roundTiesToEven), и значения флагов исключений не читаются. Нарушение данного предположения ведёт к undefined behavior.
Данная прагма в состоянии OFF позволяет ряд оптимизаций.
Большинство компиляторов не реализуют данную прагму полноценно. Для GCC схожей функциональностью обладают флаги компиляции
-frounding-math
-ftraping-math

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

Для GCC флаг
-fcx-limited-range
обладает сходной функциональностью.

Преобразование в строки символов и ввод/вывод

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

Один из них является, в каком-то смысле, особенным — интерпретация литералов с плавающей точкой. Его особенность, в частности, заключается в том, что эта операция проводится компилятором (на этапе компиляции), а не библиотекой времени выполнения (runtime library).

Стандарт IEEE-754 явно оговаривает поведение в данном случае (округление в режиме по умолчанию, в отсутствии явного указания другого поведения).

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

Краткий ответ (на момент написания этой статьи): нет.

Рассмотрим следующий пример программы на C++:

Результаты его работы:

GCC и Clang реализуют поведение, рекомендованное стандартом IEEE-754. Поведения VC также является допустимым, хотя и не рекомендуемым.

Радикальным способом решения может быть использование шестнадцатеричных констант с плавающей точкой. Однако, они отсутствуют с стандарте C++ (но присутствуют в C99). Впрочем, GCC поддерживает их в C++, в качестве расширения.

Следующий вопрос — это функции преобразования чисел в строки и обратно во время выполнения (runtime).
Стандарт IEEE754 явно оговаривает семантику этих операций (convertFromDecimalCharacter, convertToDecimalCharacter).
Язык C предоставляет ряд функций связанных с переводом между текстом и числами с плавающей точкой (printf, scanf, strtof и др.).
Должны ли эти функции реализовывать семантику, изложенную в IEEE754?
Раздел F стандарта С однозначно отвечает на этот вопрос:

На практике однако, многие реализации стандартной библиотеки пренебрегают данными требованиями. GCC придерживается данных требований довольно давно, но MSVC начала им следовать только начиная с VS2015.

Свойство «float» на практике

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

Лучше всего показать действие свойства float на практических примерах. Давайте рассмотрим их ниже.

Вставка заметки

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

Здесь код без CSS стилей:

alt=»рулетики капустные»>
— время приготовления: 25 минут

Рулетики капустные с начинкой

Отделите капустные листья от кочана, бросьте их в кипящую воду на 8 минут и дайте им остыть. Срежьте острым ножом толстые прожилки у кочана. Затем нарежьте ветчину пластинами толщиной в 5 миллиметров и положите сверху на листья капусты. Посолите и поперчите по вкусу и посыпьте сверху сыром. Закрутите листья трубочкой, оберните их салом, крепко перевяжите нитками и отправьте в разогретую духову до 200 градусов на 35 минут. При подаче блюда, посыпьте сверху зеленью.

Что такое free float

Добрый вечер! Сегодня, я хочу рассказать вам о том, что такое free float и для чего он нужен на фондовом рынке.

Несмотря на то, что соотношение спроса и предложения является основой функционирования рынка, одного только спроса для приведения цены акции в движение недостаточно. Должно быть еще и соответствующее предложение бумаг на рынке, а оно на прямую зависит от количества акций в свободном обращении, доступных для торговли или от free float. Поскольку акции компании распределены между крупными и мелкими акционерами, многие из которых не выводят бумаги на открытый рынок, конечное предложение бумаг, доступных для торговли на рынке ограничено. Поэтому выбирая акции для вложения стоит учитывать фактор их ликвидности.

Free float считается важнейшим критерием для определения цены на фондовом рынке. Рассчитать free float в теории просто — это выпущенные в обращение акции не принадлежащие инсайдерам, однако для российских компаний рассчитать free float в общем случае практически невозможно, поскольку зачастую отсутствуют данные о том сколько акций принадлежит руководителям и апеллированным компаниям. В западной практике показатель free float принят от 5 до 100%. Низкий суммарный объем торгов в количественном выражении говорит о крайне малом free float акций компании, что в свою очередь негативно сказывается на уровне ликвидности и дает возможность для ценовых манипуляций. Чем ниже free float, тем выше риски для инвесторов.

В случаях внезапного наплыва покупателей, число покупателей превысит число продавцов и владельцы акций могут не захотеть продавать их до тех пор, пока их не вынудят какие либо причины. В этом случае, игроки желающие купить бумагу, во что бы то ни стало готовы платить любую цену, в результате котировки бумаг искусственно завышаются. Аналогичная ситуация, только с противоположным знаком, возникает при наплыве продавцов. Если количество акций в свободном обращении эмитента хорошо соотносится со средним торговым оборотом, значительного движения котировок не произойдет, на рынке будет достаточно предложений для удовлетворения спроса. Однако если free float низок относительно среднего объема торгов, внезапный натиск покупателей может подвинуть цену достаточно высоко. Может случиться такая ситуация, в случае низкой ликвидности акций при желании их продать, на рынке не будет покупателей.

Факторы, которые могут привести к сокращению показателя free float

К этому может привести ряд корпоративных действий эмитента, таких как стратегическая скупка бумаг на открытом рынке, погашение казначейских облигаций, либо обратный выкуп акций. В последствии обратного выкупа акций, пакет может быть аннулирован, что повлечет увеличение стоимости остающихся в обращении акций. В таком случае, стоимость акций оставшихся в обращении увеличивается. С фундаментальной точки зрения, это объясняется тем, что при расчете рыночных мультипликаторов, таких как прибыль на акцию, являющихся для многих инвесторов ориентиром уцененности акций рынком, сокращение числа бумаг в обращении увеличивает показатель прибыли на акцию. Это как бы сигнализирует об недооцененности бумаги рынком, в результате котировки растут. Кроме того, в результате сокращения free float акций, возросший спрос не всегда подкреплен достаточным предложением, и этот дисбаланс также способствует росту стоимости акций.

Основные риски снижения объема акций в свободном обращении


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

Факторы, которые могут привести к росту объемов акций в свободном обращении

Например, наступление определенных корпоративных событий, таких как крупное размещение допэмиссии, реорганизация, повлекшая рост числа акций в свободном обращении и так далее. В этих случаях может произойти увеличение коэффициента free float.

Последствия, к которым приводит увеличение числа акций в свободном обращении

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

Наибольший показатель free float в России

В целом лидера по данному показателю на российском рынке акций определить довольно сложно, в силу недостаточной прозрачности компаний, однако в индексе РТС компанией с наибольшим free float признана нефтяная компания Лукойл.

Корректная оценка free float возможна только на прозрачном рынке, на Западе аналитики и инвесторы уделяют особое внимание числу акций в свободном обращении, поскольку это является характеристикой ликвидности бумаг и позволяет оценить риски. Также западные эксперты уделяют внимание тому, владеют ли топ-менеджеры компаний ее акциями. Если руководители не имеют акций управляемой компании, это значит, что они сами не верят в ее успех, если же акций у них слишком много, акционерам будет трудно при необходимости сменить руководство. В целом комфортным уровнем free float, учитывающим интересы мелких и крупных акционеров, является уровень 60-80%.

Вещественные типы (double, float)

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

Размер в байтах

Минимальное положительное значение

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

Константы с плавающей точкой состоят из целой части, точки (.) и дробной части. Целая и дробная части представляют собой последовательности десятичных цифр.

double a= 12.111 ;
double b=- 956.1007 ;
float c = 0.0001 ;
float d = 16 ;

Существует научный способ записи вещественных констант, зачастую этот способ записи более компактный, чем традиционный.

double c1=1.12123515e-25;
double c2=0.000000000000000000000000112123515; // 24 нуля после десятичной точки

Print ( «1. c1 = » , DoubleToString (c1,16));
// Результат: 1. c1 = 0.0000000000000000

Print ( «2. c1 = » , DoubleToString (c1,-16));
// Результат: 2. c1 = 1.1212351499999999e-025

Print ( «3. c2 = » , DoubleToString (c2,-16));
// Результат: 3. c2 = 1.1212351499999999e-025

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

Например, числа 0.3 и 0.7 представлены в компьютере бесконечными дробями, в то время как число 0.25 хранится точно, так как представляет из себя степень двойки.

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

void OnStart ()
<
//—
double three=3.0;
double x,y,z;
x=1/three;
y=4/three;
z=5/three;
if (x+y==z)
Print ( «1/3 + 4/3 == 5/3» );
else
Print ( «1/3 + 4/3 != 5/3» );
// Результат: 1/3 + 4/3 != 5/3
>

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

bool EqualDoubles( double d1, double d2, double epsilon)
<
if (epsilon
epsilon=-epsilon;
//—
if (d1-d2>epsilon)
return false;
if (d1-d2
return false;
//—
return true ;
>
void OnStart ()
<
double d_val=0.7;
float f_val=0.7;
if (EqualDoubles(d_val,f_val,0.000000000000001))
Print (d_val, «equals» ,f_val);
else
Print ( «Different: d_val = » , DoubleToString (d_val,16), » f_val = » , DoubleToString (f_val,16));
// Результат: Different: d_val= 0.7000000000000000 f_val= 0.6999999880790710
>

Необходимо отметить, что значение параметра epsilon в приведенном примере не может быть меньше предопределенной константы DBL_EPSILON. Значение этой константы 2.2204460492503131e-016. Для типа float соответствующая константа FLT_EPSILON = 1.192092896e-07. Смысл этих значений таков, что это наименьшее значение, удовлетворяющее условию 1.0+DBL_EPSILON != 1.0 (для чисел типа float 1.0+FLT_EPSILON != 1.0).

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

Илон Маск рекомендует:  Сдвигаем вверх

bool CompareDoubles( double number1, double number2)
<
if ( NormalizeDouble (number1-number2,8)==0)
return ( true );
else
return ( false );
>
void OnStart ()
<
double d_val=0.3;
float f_val=0.3;
if (CompareDoubles(d_val,f_val))
Print (d_val, «equals» ,f_val);
else
Print ( «Different: d_val = » , DoubleToString (d_val,16), » f_val = » , DoubleToString (f_val,16));
// Результат: Different: d_val= 0.3000000000000000 f_val= 0.3000000119209290
>

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

double abnormal = MathArcsin (2.0);
Print ( «MathArcsin(2.0) =» ,abnormal);
// Результат: MathArcsin(2.0) = -1.#IND

Кроме минус бесконечности существуют плюс бесконечность и NaN (не число). Чтобы определить, что данное число недействительно, можно использовать функцию MathIsValidNumber(). По стандарту IEEE они имеют специальное машинное представление. Например, плюс бесконечность для типа double имеет битовое представление 0x7FF0 0000 0000 0000.

struct str1
<
double d;
>;
struct str2
<
long l;
>;

//— начнем
str1 s1;
str2 s2;
//—
s1.d= MathArcsin (2.0); // получим недействительное число -1.#IND
s2=s1;
printf ( «1. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0xFFFF000000000000; // недействительное число -1.#QNAN
s1=s2;
printf ( «2. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0x7FF7000000000000; // наиобльшее нечисло SNaN
s1=s2;
printf ( «3. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0x7FF8000000000000; // наименьшее нечисло QNaN
s1=s2;
printf ( «4. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0x7FFF000000000000; // наибольшее нечисло QNaN
s1=s2;
printf ( «5. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0x7FF0000000000000; // плюс бесконечность 1.#INF и наименьшее нечисло SNaN
s1=s2;
printf ( «6. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0xFFF0000000000000; // минус бесконечность -1.#INF
s1=s2;
printf ( «7. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0x8000000000000000; // отрицательный ноль -0.0
s1=s2;
printf ( «8. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0x3FE0000000000000; // 0.5
s1=s2;
printf ( «9. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0x3FF0000000000000; // 1.0
s1=s2;
printf ( «10. %f %I64X» ,s1.d,s2.l);
//—
s2.l=0x7FEFFFFFFFFFFFFF; // наибольшее нормализованное число (MAX_DBL)
s1=s2;
printf ( «11. %.16e %I64X» ,s1.d,s2.l);
//—
s2.l=0x0010000000000000; // наименьшее положительное нормализованное (MIN_DBL)
s1=s2;
printf ( «12. %.16e %.16I64X» ,s1.d,s2.l);
//—
s1.d=0.7; // покажем, что число 0.7 – бесконечная дробь
s2=s1;
printf ( «13. %.16e %.16I64X» ,s1.d,s2.l);
/*
1. -1.#IND00 FFF8000000000000
2. -1.#QNAN0 FFFF000000000000
3. 1.#SNAN0 7FF7000000000000
4. 1.#QNAN0 7FF8000000000000
5. 1.#QNAN0 7FFF000000000000
6. 1.#INF00 7FF0000000000000
7. -1.#INF00 FFF0000000000000
8. -0.000000 8000000000000000
9. 0.500000 3FE0000000000000
10. 1.000000 3FF0000000000000
11. 1.7976931348623157e+308 7FEFFFFFFFFFFFFF
12. 2.2250738585072014e-308 0010000000000000
13. 6.9999999999999996e-001 3FE6666666666666
*/

Float sum(float a, float b, float c)

return S;>

Пример. Функция находит большее из двух переменных. Функция имеет формальные параметры и два оператора return.

int max(int x, int y)

y)return x;

else return y;>

Пример. Функция выводит значение переменной на экран. Функция имеет один формальный параметр и не имеет оператора return.

void prn1(int x)

Пример. Функция выводит строку на экран. Функция не имеет фор­мальных параметров и оператора return.

void prn2()

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

имя_функции(список фактических параметров)

где список_фактических_параметров – это либо пусто, либо void, либо фактические параметры (константы или заранее определенные переменные, переменные с преобразованием типов, выражения).

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

int max(int x, int y)

y)return x; else return y;>

void main()

res1=max(a,20); // res1=20

res2=max(int(f),a+30);> // res2=55

int func1(int a, int b) //Определение функции

float sqr(float f, float g) //Определение функции

void main()

res1=func1(am,bm); //Вызов функции

float em=2.5,gm=3.0,fm=4.2,res2,res3;

res2=sqr(fm,gm); //Вызов функции

res3=sqr(fm+0.5,sqr(em,gm)); //Вызов функции

int res4=(int)sqr(em,float(am)); > //Вызов функции

Если функция определена после функции main() или в другом файле, то до первого обращения к функции она должна быть описана. Описание функции называется прототипом. Это необходимо для проверки компилятором соответствия типов передаваемых в функцию параметров и возвращаемых значений. В прототипе можно не указывать имена формальных параметров. В конце прототипа обязательна точка с запятой. Примеры прототипов:


float sum(float a, float b, float c);

int max(int, int y);

float sqr(float, float g);

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

#include

int sum(int, int);//Прототип функции – описание функции

void main()

a=sum(b, g); //Вызов функции

printf(«Сумма=%d\n», a); >

int sum(int arg1, int arg2) //Определение функции

2.2 Передача параметров в функции по значению и по указателю

В языке С++ передача параметров (кроме указателей и массивов) в функции при их вызове осуществляется по значению. Это означает, что для передаваемых (фактических) параметров в функции создаются копии этих параметров. Для формальных параметров выделяется память, в которую заносятся значения фактических параметров. Действия, производимые с этими параметрами (копиями) в функции не влияют на переменные вне функции, т.е. на фактические пере­менные. Формальные параметры недоступны вне тела функции. При выходе из функции выделенная для них память освобождается.

#include

void func(int intg,float fltp)

intg+=10; fltp*=2;

printf(«intg_n=%d fltp_n=%f\n»,intg,fltp);>

void main()

func(i,f);

В результате работы программы на экран выведется:

intg=200 &intg=8FD8:0FF2 fltp=100.25 &fltp=8FD8:0FF4

intg_n=210 fltp_n=200.5

i=200 &i=8FD8:0FFC f=100.25 &f=8FD8:0FF8

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

Пример. В функцию передаются указатели на переменные и значения этих переменных меняются местами:

#include

void swap(int *a, int *b) //Определение функции

int tmp=*a; *a=*b; *b=tmp;

printf(«*a_n=%d *b_n=%d\n»,*a,*b);>

void main()

swap(&i,&j); //Вызов функции

printf(«i=%d j=%d\n»,i,j);>

В результате работы программы на экран выведется:

&i=8FD8:0FFE i=5 &j=8FD8:0FFC j=60

&a=8FD8:0FF4 a=8FD8:0FFE *a=5

&b=8FD8:0FF8 b=8FD8:0FFC *b=60

*a_n=60 *b_n=5

i=60 j=5

2.3 Функции и массивы

При передачемассива в функцию в качестве параметра указыва­ется имя массива. Поскольку имя массива – это указатель-константа, то в функцию передается адрес начала массива и все действия внутри функции производятся именно с элементами массива оригинала. При этом список формальных параметров в заголовке функции имеет две равноправные формы: (покажчик-константа

int func1(int arr[])

илиint func2(int *mass)

В обоих случаях в функции создается копия указателя соответст­вующего типа, который действует внутри функции как обычный ука­затель-переменная и может изменять свое значение. Например, arr++. Доступ к элементам массива внутри функции может осуществляться как с помощью индексов (arr[1], arr[i]), так и применяя опера­цию разыменования указателя ( *(arr+1), *(arr+i)).

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

Есть два способа определения конца массива: 1) в качестве одного из параметров в функцию передается размер массива; 2) последний элемент массива задается каким-либо уникальным значением, которое анализируют в функции.

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

#include

int sum(int N,int x[]) //Определение функции

for(int i=0;i

int len(char *); //Прототип функции

void main()

printf(«Длина 1-ой строки=%d»,len(name)); // 10

char *str=»Высшая математика»;

printf(«Длина 2-ой строки=%d»,len(str)); > // 17

int len(char *c) //Определение функции

while(c[i++]);

return i-1; > //длина строки без учета символа ‘\0

Пример. Функция изменяет значения элементов массива, поменяв их на квадраты этих значений, тип функции void


#include

void exch(int, int []); //Прототип функции

void main()

printf(«Массив до изменения: «);

for(int i=0;i

int def(int a=10, int b=3)

void main()

res1=def(); // 10*3=30

res2=def(am); // 2*3=6

res3=def(am,bm); // 2*5=10

printf(«res1=%d res2=%d res3=%d\n»,res1,res2,res3); >

В результате работы программы на экран выведется:

res1=30 res2=6 res3=10

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

Пример. Функция находит сумму 3-х переменных

#include

int sum(int,int=5,int=10); //Прототип функции

void main()

s1=sum(am); // 20+5+10=35

s2=sum(am,bm); // 20+50+10=80

s3=sum(am,bm,cm); // 20+50+100=170

printf(«s1=%d s2=%d s3=%d\n»,s1,s2,s3);>

int sum(int a,int b,int c) //Определение функции

В результате работы программы на экран выведется:

s1=35 s2=80 s3=170

2.5 Функции с переменным числом параметров

Функции с переменным числом параметров– это функции, в ко­торых количество и типы параметров определяются только во время их вызова. Синтаксис определения прототипа таких функций:

тип имя(спецификация явных параметров. );

Последняя запятая необязательна. Многоточие сообщает компи­лятору, что не нужно проводить дальнейший контроль соответствия количества параметров и их типов при обработке вызова. Переход в списке от параметра к параметру осуществляется с помощью указате­ля, тип которого является типом переменной. При увеличении указа­теля на единицу осуществляется переход к следующей переменной такого же типа. В ВС31 функции с переменным числом параметров не работают с типамиchar, unsigned char, float.

В таких функциях существуют два способа определения коли­чества параметров: 1) передача в функцию в списке фактических параметров информации об их количестве; 2) добавление параметра–индикатора в конец списка фактических параметров.

Пример. В функцию передается в списке явных параметров количес­тво элементов, которые суммируются.

#include

int sumi(int i. )//Определение функции

int sum=0;

for(;i;i—) sum+=*(++num);//вычисляем сумму со 2-го элемента

return sum;>

double sumd(int i,double d. )//Определение функции

double sum=0.0;

for(;i;i—) //1-й параметр – число переменных в списке

sum+=*(ptr++);

return sum;>

void main()

s1=sumi(3,a1,a2,a3); //сумма 3-х чиселa1,a2,a3

s2=sumi(6,1,a1,3,a2,a3,4); //сумма 6-и чисел

double d1=5.7, d2=1.3,s3;

s3=sumd(4,d1,1.25,d2,2.5); //сумма 4-х чисел

printf(«s1=%d s2=%d s3=%.2lf\n»,s1,s2,s3);>

В результате работы программы на экран выведется:

s1=60 s2=68 s3=10.75

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

#include

#define term 0.0

double mult(double arg. ) //Определение функции

if(*ptr==0.0) return 0.0;

for(;*ptr!=term;ptr++)

a*=*ptr;

return a;>

void main()


md1=mult(a,b,0.3,term);

md2=mult(0.5,a,4.0,b,1.1,term);

printf(«md1=%.2lf md2=%.2lf\n»,md1,md2);>

В результате работы программы на экран выведется:

md1=1.50 md2=11.00

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

Макрокомандаvoid va_start (va_list param, последний явный параметр)связываетвспомогательный параметрparam с последним явным параметром в списке.

Макрокоманда type va_arg (va_list param,type) переме­щает указательparamна число байтзаданного типа type.

Макрокоманда va_end (va_list param) вызывается после обработки списка и организует корректный возврат из функции (вместо оператора return).

2.6 Передача параметров в функцию main()

В функцию main(),как и в любую другую функцию, могут передаваться параметры. Для передачи параметров в функциюmain() ее следует описать в таких формах:

[тип] main(int argc, char **argv)

[тип] main(int argc, char **argv, char **envp)

[тип] – тип функции mainможет быть void илиint.

Параметр int argc определяет число слов в командной строке.

Параметр char **argv ‑ указатель на массив строк, вводимых из командной строки. Массив строк –это массив указателей, являющихся адресами первых символов этих строк. Размер этого массива строк равен argc. Нулевое слово, на которое указывает указатель argv[0], всегда является спецификацией запускаемой на выполнение програм­мы (именем программы с расширением .exe).

Параметрchar **envp ‑ это указатель на массив указателей на строки среды программы. С помощью этого параметра в программу можно передать всю информацию среде окружения программы, ко­торая определяет некоторые особенности операционной системы и др.

В следующих примерах демонстрируется передача параметров в функциюmain.Для работы программ их необходимо запустить из командной строки, например в среде FAR, NC, VC, DN и др.

#include

#include

int main(int argc,char**argv,char**envp)

for(int i=0;i

printf(«argv[%d]=%s\n»,i,argv[i]);

getch();

puts(«Среда окружения»);

while(*envp) puts(*envp++);

getch();

return 0;>

Пусть исполняемый файл этой программы prog1.exe располо­жен в корневом каталоге диска C:\ . Тогда, если в командной строке набрать c:\>prog1.exe my age 19, то результат работы программы может быть такой:

argv[0]=C:\PROG1.EXE

argv[1]=my

argv[2]=age

argv[3]=19

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: Увлечёшься девушкой-вырастут хвосты, займёшься учебой-вырастут рога 9788 — | 7664 — или читать все.

188.64.174.135 © studopedia.ru Не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования. Есть нарушение авторского права? Напишите нам | Обратная связь.

Отключите adBlock!
и обновите страницу (F5)

очень нужно

Модель памяти C# в теории и на практике

Продукты и технологии:

C#

В статье рассматриваются:

  • спецификация языка C#;
  • переупорядочение операций с памятью;
  • шаблоны взаимодействия потоков;
  • interlocked-операции и барьеры памяти.

Это первая из двух статей, в которых пойдет долгое повествование о модели памяти в C#. В первой части поясняются гарантии модели памяти C# и показываются шаблоны кода, которыми обусловлены эти гарантии; во второй части будет подробно рассмотрено, как данные гарантии достигаются на разных аппаратных архитектурах в Microsoft .NET Framework 4.5.

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

Если _data и _initialized — обычные (т. е. неизменяемые) поля, компилятору и процессору разрешается такое переупорядочение операций, чтобы Init выполнялся так, будто он написан следующим образом:

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

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

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

Но в многопоточной программе порядок присваиваний может иметь значение, поскольку другой поток может считывать эти поля, пока Init находится в середине выполнения. Соответственно в переупорядоченной версии Init другой поток может наблюдать _initialized=true и _data=0.

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

Однако, даже если компилятору и процессору разрешено переупорядочивать операции с памятью, это не означает, что на практике они всегда так делают. Многие программы, которые содержат «ошибку» согласно абстрактной модели памяти C#, будут по-прежнему корректно выполняться на конкретном аппаратном обеспечении, где работает определенная версия .NET Framework. В частности, процессоры x86 и x64 переупорядочивают операции лишь в некоторых сценариях весьма узкого применения, и аналогично JIT-компилятор в CLR не выполняет многие трансформации, которые ему разрешены.

Модель памяти C# разрешает переупорядочение операций в каком-либо методе, только если поведение при однопоточном выполнении не меняется.

Хотя абстрактная модель памяти C# — это то, что вы учитывать при написании нового кода, понимание истинной реализации модели памяти в различных аппаратных архитектурах может оказаться весьма полезным, в частности если вы пытаетесь разобраться в поведении существующего кода.

Модель памяти C# согласно ECMA-334

Авторитетное определение модели памяти C# дано в Standard ECMA-334 C# Language Specification (bit.ly/MXMCrN). Давайте обсудим эту модель в том виде, как она определена в данной спецификации.

Переупорядочение операций с памятью Согласно ECMA-334, когда поток считывает в C# участок памяти, записанный другим потоком, «читатель» может увидеть устаревшее значение. Эту проблему иллюстрирует рис. 1.

Рис. 1. Код, подверженный риску переупорядочения операций с памятью


Допустим, что Init и Print вызываются параллельно (т. е. в разных потоках) в новом экземпляре DataInit. Если вы посмотрите код Init и Print, вам может показаться, что Print может выводить только «42» или «Not initialized». Но Print также может вывести «0».

Модель памяти C# разрешает переупорядочение операций в каком-либо методе, только если поведение при однопоточном выполнении не меняется. Например, компилятор и процессор могут переупорядочить операции метода Init так:

Это переупорядочение не изменило бы поведение метода Init в однопоточной программе. Однако в многопоточной программе другой поток мог бы считать значения полей _initialized и _data после того, как Init модифицировал одно поле, но не успел сделать это со вторым, а затем последующее переупорядочение может изменить поведение программы. В результате метод Print мог бы вывести «0».

Переупорядочение Init — не единственный возможный источник проблем в этом примере кода. Даже если операции записи в Init не переупорядочиваются, операции чтения в методе Print могут быть трансформированы:

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

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

Илон Маск рекомендует:  Что такое код function_exists

Изменяемые поля Язык программирования C# предоставляет изменяемые поля (volatile fields), которые ограничивают то, как могут быть переупорядочены операции с памятью. В спецификации ECMA утверждается, что изменяемые поля предоставляют семантику получения-освобождения (acquire­release) (bit.ly/NArSlt).

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

Чтение 1 и чтение 3 — операции с неизменяемыми полями, а чтение 2 — операция с изменяемым полем. Чтение 2 нельзя переупорядочить с чтением 3, но можно — с чтением 1. В табл. 1 показаны допустимые переупорядочения в теле Foo.

Табл. 1. Допустимое переупорядочение операций чтения в AcquireSemanticsExample

int a = _a; // чтение 1

int b = _b; // чтение 2 (изменяемое поле)

int c = _c; // чтение 3

int b = _b; // чтение 2 (изменяемое поле)

int a = _a; // чтение 1

int c = _c; // чтение 3

int b = _b; // чтение 2 (изменяемое поле)

int c = _c; // чтение 3

int a = _a; // чтение 1

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

Записи 1 и 3 — операции с неизменяемыми полями, а запись 2 — операция с изменяемым полем. Запись 2 нельзя переупорядочить с записью 1, но можно — с записью 3. В табл. 2 показаны допустимые переупорядочения в теле Foo.

Табл. 2. Допустимое переупорядочение операций записи в ReleaseSemanticsExample

_a = 1; // запись 1

_b = 1; // запись 2 (изменяемое поле)

_c = 1; // запись 3

_a = 1; // запись 1

_c = 1; // запись 3

_b = 1; // запись 2 (изменяемое поле)

_c = 1; // запись 3

_a = 1; // запись 1

_b = 1; // запись 2 (изменяемое поле)

Я вернусь к семантике получения-освобождения в подразделе «Публикация через изменяемое поле» далее в этой статье.

Атомарность Другая проблема C#, о которой нужно знать, заключается в том, что значения не обязательно записываются в память атомарно. Рассмотрим этот пример:

Если один поток повторно вызывает SetValue, а другой вызывает GetValue, то второй поток может наблюдать значение, которое никогда не записывалось первым потоком. Например, если первый поток попеременно вызывает SetValue со значениями Guid (0,0,0,0) и (5,5,5,5), то GetValue может наблюдать (0,0,0,5), (0,0,5,5) или (5,5,0,0), хотя ни одно из этих значений никогда не присваивалось через SetValue.

Причина такого «разрыва» в том, что присваивание _value = value не выполняется атомарно на аппаратном уровне. Аналогично чтение _value тоже не выполняется атомарно.

Спецификация ECMA по C# гарантирует, что следующие типы будут записываться атомарно: ссылочные типы, bool, char, byte, sbyte, short, ushort, uint, int и float. Значения других типов, включая пользовательские значимые типы, могут помещаться в память набором атомарных операций записи. В итоге поток-«читатель» мог бы наблюдать рваные значения, состоящие из частей различных значений.

Один из подвохов в том, что типы, которые обычно считываются и записываются атомарно (например, int), могут считываться и записываться не атомарно, если значение неправильно выровнено в памяти. В нормальных условиях C# гарантирует, что значения выравниваются в памяти правильно, но пользователь может переопределить это выравнивание с помощью класса StructLayoutAttribute (bit.ly/Tqa0MZ).

Оптимизации без переупорядочения Некоторые оптимизации компилятора могут вводить или исключать определенные операции с памятью. Так, компилятор может заменить повторяемые операции чтения какого-либо поля одним чтением. Аналогично, если код считывает поле и сохраняет значение в локальной переменной, а затем повторно считывает эту переменную, то компилятор мог бы вместо этого выбрать повторное чтение поля.

Поскольку ECMA-спецификация C# не исключает оптимизации без упорядочения, они предположительно разрешены. По сути, как будет рассматриваться во второй части, JIT-компилятор действительно выполняет оптимизации этих типов.

Один из подвохов в том, что типы, которые обычно считываются и записываются атомарно (например, int), могут считываться и записываться не атомарно, если значение неправильно выровнено в памяти.

Шаблоны взаимодействия потоков

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

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

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

Рис. 2. Взаимодействие потоков с блокировкой

Типы данных float и double в языке программирования Java

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

Java позволяет использовать 8 простых типов данных:

byte, short, int, long – целочисленные,
float, double — вещественные обычной и двойной точности,
boolean — булевские (логические, представляющие истину или ложь),
сhar — символьные, представляющие символы Unicode.

Float и double применяются для выполнения инженерных и научных расчетов.

Если данные по смыслу задачи могут иметь дробную часть, применяют вещественные (синоним — действительные) данные.

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

Тип double содержит почти вдвое больше значащих цифр, чем float, и больший диапазон показателя степени.

В вещественных данных три части — знак s (равен 1 или -1) мантисса m и порядок p. Числа представлены в двоичной системе. Мантисса m хранит значащие цифры числа. Произведение мантиссы и основания системы, возведенного в степень, равную порядку, дает истинную величину числа s.

С вещественными данными можно выполнять обычные арифметические операции (+-*/), результат которых — тоже вещественное число. Сравнение действительных данных выполняется операциями , =, ==, != (меньше, больше, не больше, не меньше, равно, не равно). Следует проявлять внимательность при сравнении действительных данных и действительных литералов, поскольку действительные данные представляются с погрешностью.

Каждому простому типу в языке Java соответствует объектный тип — так называемый класс-оболочка (wrapper class). Классы-оболочки (для float и double это Float и Double) содержат полезные и интересные методы для проверок свойств данных или для их преобразования в другие типы.

Подробная информация о классах-оболочках имеется в документации по Java.


Float в теории и на практике

Float — это свойство CSS для позиционирования элементов. Для того чтобы понять его назначение и происхождение, можно обратиться к полиграфическому дизайну. В компоновке при печати, изображения могут располагаться на странице так, чтобы текст «обтекал» их. Обычно это так и называется: «обтекание текстом».

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

В веб-дизайне, элементы страницы с установленным свойством float, ведут себя точно также как и изображения в полиграфии, когда текст «обтекает» их. Такие элементы являются частью основного потока веб-страницы. Однако всё обстоит иначе, если элементы используют абсолютное позиционирование. Абсолютно позиционированные элементы удаляются из основного потока страницы, подобно примеру выше, когда в полиграфии текст игнорирует изображения. Такие элементы не влияют на позицию остальных элементов, соприкасаются они или нет.

Установка свойства float происходит следующим образом:

Всего есть 4 значения для свойства float. Left и right используются для соответствующих направлений. None (по умолчанию) — обеспечивает, что элемент не будет «плавать». И inherit, которое говорит, что поведение должно быть такое же, как и у родительского элемента.

Для чего можно использовать float?

Помимо обтекания текстом изображений, float может использоваться для создания макета всего сайта.

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

Такое же расположение объектов может быть достигнуто путём использования позиционирования. Объекту-контейнеру присваивается относительное (relative) позиционирование, а объекту с изображением — абсолютное (absolute). В этом случае аватар не повлияет на положение текста.

Отмена свойства float

Для float, родственное свойство — clear. Любой элемент, у которого установлено свойство clear, не будет поднят вверх, как от него ожидается, а отобразится ниже, после float-элементов. Возможно, пример на картинке объяснит лучше, чем слова.

В примере, сайд-бар прижат к правому краю (float: right;), а его высота меньше, чем область основного контента. Поэтому footer будет поднят выше, поскольку для него хватает высоты и этого требует поведение float. Чтобы исправить ситуацию, ему необходимо установить свойство clear, которое гарантирует, что элемент выведется ниже float-элементов.

Свойство clear может принимать четыре значения. Both, наиболее используемое, применяется для отмены float каждого из направлений. Left и Right — используются для отмены float одного из направлений. None — по умолчанию, обычно не используется, за исключением случаев, когда необходимо отменить значение clear. Значение inherit было бы пятым значением, но оно странным образом не поддерживается в Internet Explorer. Отмена только левого или правого float, встречается гораздо реже, но, безусловно, имеет свои цели.

Большой коллапс

Ещё одна удивительная вещь при работе со свойством float — это то, что его использование может влиять на родительский элемент. Если такой элемент содержит только float-элементы, то он буквально схлопывается, то есть его высота равна нулю. Это не всегда заметно, если у родительского элемента не установлен какой-либо видимый фон.

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

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

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

Способы отмены float

Если вам известно, что следом после float-элементов, всегда будет выводится какой-либо другой элемент (например футер), то вам достаточно ему установить свойство clear: both;, как в примере выше, и заниматься дальше своими делами. Это идеальный вариант, поскольку он не требует каких-либо хаков, или дополнительных элементов. Конечно не всё в нашей жизни так гладко и бывают случаи когда такого способа не достаточно. Поэтому необходимо иметь несколько дополнительных способов в своём арсенале.

    Метод пустого div-а. Используется, в буквальном смысле, пустой div.

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

Для более лучшего визуального представления было бы неплохо объединить подобные блоки. Например мы хотим, чтобы каждый тип начинался с новой строки, в нашем случае тип элемента определяется цветом. Мы можем использовать метод с overflow или «метод простой очистки», если у каждой группы есть свой элемент-контейнер. Или же мы можем использовать метод пустого div-а между каждой из групп. Три элемента-контейнера, или три пустых div-а, что лучше для вашей задачи — решать вам.

Проблемы с float

Float часто стараются обходить, поскольку работать с ними надо очень аккуратно. Большинство ошибок пришло вместе с IE6. Поскольку всё больше и больше веб-дизайнеров отказываются от поддержки IE6, то вас могут и не волновать эти проблемы. Но для тех, кому не всё равно, вот краткий список.

  • «Выталкивание» (pushdown). Возникает когда элемент внутри float-элемента оказывается шире его (обычно это изображения). Большинство браузеров обработает такие элементы вне float-структуры и вёрстка не будет сломана. IE расширит элемент, чтобы изображение влезло, зачастую это ломает дизайн. На картинке представлен пример, как изображение торчит из основного контента и таким образом «выталкивает» сайд-бар вниз. Самый просто способ избежать этого — это проверить что все ваши изображения подходят по ширине. Можно использовать overflow: hidden;, чтобы обрезать выступающую часть.
  • Двойной внешний отступ. Ошибка проявляющаяся в IE6, в случае если вы устанавливаете внешний отступ в том же направлении, в котором у вас указан float. В этом случае отступ удваивается. Чтобы исправить это, необходимо установить плавающему (float) элементу свойство display: inline;, не беспокойтесь, элемент по прежнему будет блочным.
  • Трёх-пиксельный прыжок (3px Jog). Ошибка, которая проявляется следующим образом: текст, который расположен рядом с float-элементом неожиданно съезжает на 3 пикселя. Чтобы избежать этого, необходимо установить ширину или высоту пострадавшему тексту.
  • В IE7 существует Ошибка нижнего внешнего отступа (Bottom Margin Bug) — возникает когда элемент с установленным свойством float, содержит в себе ещё один float-элемент. В таких случаях, нижний внешний отступ дочернего элемента игнорируется. Для обхода этой проблемы необходимо использовать внутренний отступ родительского элемента, вместо внешнего отступа дочернего.

Альтернативы float

Если вам необходимо обтекание картинки текстом, то альтернатив нет. Но для макета страницы, определённо есть выбор. Существуют очень интересные подходы, в которых комбинируется гибкость float с мощью абсолютного позиционирования. В CSS3 есть, так называемый, Модуль разметки шаблона (Template Layout Module), который в будущем предоставит достойную альтернативу float.

CSS Float: описание, свойства

Float — одна из базовых функций языка CSS (Cascading Style Sheets — форматирование каскадных таблиц). Этот язык существует с 1996 года и до сих пор продолжает развиваться. На данный момент разработчики используют уже третью версию CSS. С помощью языка программирования CSS возможно создать вполне красивый и приятный сайт, который не будет казаться устаревшим или неудобным для пользователя, даже если совершенно не применять JavaScript. Современные возможности третьей версии позволяют это сделать.

Также разработчики могут использовать более удобные варианты форматирования, такие как Flexbox или Position для смены места элемента на сайте, но обо всем по порядку. Для начала следует разобраться с преимуществами и недостатками свойства Float.

CSS Float — зачем он нужен?

Float — свойство для позиционирования элементов. Каждый день его можно наблюдать на страницах газет и журналов, смотря на картинки и текст, который очень аккуратно обтекает их вокруг. В мире кодов HTML и CSS при использовании функции Float должно произойти то же самое. Но стоит помнить, что редактирование изображений далеко не всегда является основным назначением этой функции. Ее можно использовать для создания популярного расположения элементов сайта в две, три, четыре колонки. На самом деле, свойство Float CSS применяется практически к любому html-элементу. Зная основы редактирования расположения элементов с помощью функции Float, а затем и Property, создать любой дизайн сайта не составит особого труда.

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

CSS Float описание свойства

В действительности умение пользоваться свойством Float является очень хорошим тузом в рукаве для любого веб-дизайнера. Но, к сожалению, недостаточное понимание того, как работает эта функция, может привести к столкновениям элементов сайта и другим огорчениям подобного рода. Раньше также подобные ситуации происходили из-за багов в браузерах. Сейчас секрет того, как правильно использовать свойство Float, будет раскрыт, и никаких проблем с этим возникнуть больше не должно.

У свойства Float есть четыре значения:

Для тех, кто знает английский, значения параметров свойства Float должны быть понятны. Но для тех, кто не знает, можно привести небольшое объяснение. Параметр :left; перемещает тело элемента в самый крайний левый угол родительского элемента. То же происходит (только в другую сторону) при bcgjkmpjdfybb параметра :right;. Значение :inherit; приказывает элементу взять на себя те же настройки, что и у родительского. Такие элементы еще называются дочерними, так как они располагаются непосредственно внутри родительского в html-коде. А свойство :none; позволяет элементу не нарушать обычного течения документа, оно устанавливается по умолчанию для всех частей кода.

Как Float работает?

Свойство Float CSS работает достаточно просто. Все, что было описано выше, можно сделать без особого труда. Дальше все будет так же просто. Но прежде чем продолжить изучение свойства Float, стоит немного разобраться в теории. Каждый элемент веб-сайта является блоком. Легко убедиться в этом, открыв консоль в Google Chrome нажатием Ctrl + Shift + J. Текст, заголовок, картинка, ссылки и все остальные составные части сайта будут отображаться блоками, просто разных размеров. Изначально все эти блоки идут друг за другом. Как видно на примере ниже, строки кода идут друг за другом, поэтому и отображаться они будут строго друг за другом.

Это называется normal flow (нормальное течение). При таком течении все блоки ложатся друг на друга (не пересекая тела элементов) вертикально. Изначально все содержимое веб-страницы расположено именно таким образом. Но при использовании, например, свойства языка CSS Float Left, элемент покидает свое естественное положение на странице и смещается в крайнее левое положение. Такое поведение неизбежно приводит к столкновению с теми элементами, которые так и остались в нормальном течении.

Илон Маск рекомендует:  nav в HTML

Другими словами, элементы вместо того, чтобы располагаться вертикально, теперь находятся рядом друг с другом. Если у родительского элемента достаточно места, чтобы он смог разместить два дочерних внутри себя, то столкновения не происходит, если же нет, то наложение одного объекта на другой неизбежно. Это чрезвычайно важно запомнить для понимания работы свойства Float CSS.

Функция Clear для решения проблем

У функции Float есть сердечный друг — Clear. Вместе они — не разлей вода. Обе эти функции дополняют друг друга и делают разработчика счастливым. Как было указано выше, соседние элементы выходят из своего нормального течения и тоже начинают «плавать», как и элемент, к которому применили свойство Float (например, CSS Float Top). В итоге вместо одного плавающего элемента получаются два, причем совсем не в том месте, где их намеревался расположить разработчик. С этого момента как раз и начинаются все проблемы.

У функции Clear есть пять значений:

По аналогии можно понять, когда лучше всего применить функцию Clear. Если у нас написана строчка в коде Float:right; (CSS-код имеется ввиду), то функция должна быть Clear:right;. То же самое качается и свойства Float:left; дополнять его будет Clear:left;. При написании кода Clear:both; получится, что элемент, к которому применяется эта функция, будет находиться ниже элементов, к которым применена функция Float. Inherit берет настройки у родительского элемента, а none не вносит никаких изменений в структуру сайта. Если понять, как работают функции Float и Clear, можно написать уникальный и необычный HTML и CSS Float-код, который сделает ваш веб-сайт единственным в своем роде.

Использование Float для создания колонок

Особенно полезно свойство Float при создании колонок на сайте (или расположении контента CSS Float по центру веб-страницы). Именно такой код является самым практичным и удобным, поэтому стоит рассмотреть несколько вариантов создания привычного шаблона сайта, состоящего из двух колонок. Для примера возьмем стандартный веб-сайт с контентом слева, навигационной панелью (navigation bar) справа, заголовком и нижним колонтитулом. Код будет таким:

Теперь необходимо разобраться, что же здесь написано. Родительский элемент, в котором находится основная часть html-кода, назван контейнером (container). Он позволяет не дать элементам, к которым применена функция Float, разбрестись в разные стороны. Если бы его не было, то эти элементы уплыли бы до самых границ браузера.

Затем, в коде идут #content и #navigation. К этим элементам применяется функция Float. #content отправляется налево, а #navigation идет направо. Это необходимо для создания сайта из двух колонок. Обязательно нужно указать ширину, чтобы объекты не наложились друг на друга. Ширину можно указывать и в процентах. Так даже удобнее, чем в пикселях. Например, 45 % для #content и 45 % для #navigation, а оставшиеся 10 % отдать свойству margin.

Свойство Clear, которое находится в #footer, не дает нижнему колонтитулу последовать за #navigation и #content, а оставляет его на том же самом месте, на котором он и находился. Что может произойти? если не указать свойство Clear? В данном коде #footer просто-напросто пойдет вверх и окажется под #navigation. Это случится из-за того, что у #navigation достаточно места для размещения еще одного элемента. На этом наглядном примере очень хорошо видно, как свойства Clear и Float дополняют друг друга.

Неприятности, с которыми можно столкнуться при написании кода

Указанные выше примеры достаточно просты. Но и с ними могут возникнуть проблемы. Вообще, на самом деле, множество неожиданных неприятностей может случиться с функцией Float. Как бы ни было странно, но проблемы обычно возникают не с CSS, а с html-кодом. Место, где расположен элемент с функцией Float в html-коде, напрямую влияет на работу последней. Для того чтобы избежать различного рода затруднений, лучше всего придерживаться простого правила — располагать элементы с функцией Float первыми в коде. Почти всегда это работает и сводит к минимуму их неожиданное поведение.

Столкновение элементов

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

Из-за того, что эти элементы сначала находятся в нормальном течении, а затем оно нарушается свойством Float, браузер может убрать их со страницы сайта. Однако не стоит отчаиваться, ведь решение простое и ясное — использовать свойство Cear. Возможно, что из всех способов выхода из этой проблемы применение Clear является самым действенным.


Но проблему столкновения элементов веб-страницы можно решить и по-другому. Существует еще по крайней мере два способа:

  • использование функции Position;
  • применение Flexbox.

Функция Position порой является неплохой альтернативой CSS Float. По центру веб-страницы в случае применения Position лучше всего расположить изображения. Если правильно применить значения :absolute и :relative, то элементы встанут на свои места и не будут накладываться друг на друга.

Разбор кода функции Position и Float

Стоит разобраться подробнее с тем, как в коде HTML и CSS Float заменить на Position. На самом деле это очень просто. Допустим, есть элемент #container и #div.

Float и clear — CSS свойства для плавающих элементов при блочной верстке

Здравствуйте, уважаемые читатели блога Goldbusinessnet.com! После весьма существенного перерыва я решил продолжить тему изучения CSS и сегодняшняя статья будет посвящена созданию плавающих элементов посредством float, на практических примерах рассмотрим действие данного правила вкупе со свойством clear для создания колонок и горизонтального меню.

Для непосвященных, думаю, правильнее будет для начала ознакомиться с другими материалами по каскадным таблицам стилей. Напомню, что все статьи на данную тему находятся в разделе «Учебник CSS», в котором вы сможете почерпнуть необходимую информацию.

Плавающие элементы встречаются также в HTML при необходимости создать обтекание тех же изображений текстом (атрибут align тега img с параметрами left и right). Так что этот аспект весьма популярен при разработке содержания вебстраниц.

На протяжении сегодняшней публикации разберем действия правила float (left, right, none) и clear в том числе применительно к тегам DIV и SPAN, которые являются основой при блочной верстке. Конечно, на современном этапе подавляющее большинство использует при создании сайта прогрессивные CMS (в частности, WordPress). Однако, поверьте, что знания основ стилей и языка гипертекстовой разметки сослужат вам добрую службу в дальнейшем.

Как создаются плавающие элементы в CSS с помощью float

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

Одним из таких инструментов является, к примеру, CSS position (relative, absolute, fixed), о котором подробнее можете почитать по приведенной ссылке. Ну а другим средством, позволяющим изменить порядок стандартного отображения вебэлементов, как раз и служит правило float.

Данные по любому свойству (propety) CSS и его значениям можно почерпнуть со страницы спецификации W3C, где дана полновесная информация (данные по второй версии таблиц стилей, но это справедливо и для CSS3, которая уже действует официально, хотя до конца не доработана):

Как видите, float может принимать один из трех возможных параметров (left, right, none) и наследует значение родителя (inherit). Параметр float none применяется по умолчанию и означает, что элементы будут отображаться в порядке, соответствующем обычному потоку. А вот right или left позволяют создавать плавающие блоки со смещением вправо или влево соответственно.

Если помните, наиболее часто используемые HTML теги делятся на строчные и блочные, которые ведут себя по-разному (вообще, тип отображения всех элементов реализуется средствами CSS с помощью свойства Display). Блочные занимают всю доступную ширину, если не указано значение width. Высота определяется содержимым, ежели параметр height не прописан.

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

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

С тем, чтобы убедиться в правильности выше сказанного, возьмем два строчных тега, прописав для них свойства width и height, а также один блочный тег. С целью обеспечения наглядности зададим цветовые оттенки для каждого блока с помощью background (аналогично можно использовать background-color):

Результирующая картинка будет следующей:

Как видите, мы получили практическое подтверждение, что указанные высота (height:50px) и ширина (width:450px) не работают в обычных условиях для тега SPAN, который является строчным. Далее попробуем прописать свойство float right для первого строчного вебэлемента и float left для второго:

В итоге получаем:

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

Более того, вебэлементы, определяемые строчным тегом SPAN, по другому стали взаимодействовать с соседним контейнером DIV. Если далее убрать, скажем, атрибут width из стилей обоих тегов SPAN, то их ширина будет определяться содержанием (в нашем случае длиной текста с названием элементов):

Теперь содержимое блока DIV начинает обтекать справа вэбэлемент с float: left. Есть смысл более наглядно ознакомиться с результатами конкретных практических изысканий на этой вебстранице, где вы можете сами попробовать менять область просмотра и понаблюдать, как поведут себя блоки по отношению друг к другу:

Подытоживая, определим некоторые особенности, которые будут присущи контейнеру с тем или иным значением свойства float (right или left):

  • Элемент смещается к левому или правому краю;
  • Он становится блочным вне зависимости от того, каким он был до этого;
  • Ведет себя таким образом, как будто соседних блочных вэбэлементов (с правилом display:block) не существует. В этом вы можете убедиться, если еще разок взгляните на скриншоты данного раздела статьи;
  • В то же время строчные теги (display:inline) будут обтекать плавающие блоки. Если вновь посмотрите на предыдущий скриншот, то заметите, что содержание DIV контейнера («Блочный элемент») обтекает SPAN с float:left справа.
  • Если явно не указывать ширину плавающего блока (в нашем примере width:450px), то она будет определена его содержимым;

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

Каким образом сделать горизонтального меню посредством CSS (float)

Далее разберем вполне конкретное задание по созданию горизонтального меню с помощью плавающих блоков, которое весьма часто используется при разработке вебсайтов. Сначала сконструируем маркированный список HTML посредством тега UL, код которого будет выглядеть так:

Получим примерно следующее:

Теперь немного подредактируем полученное меню с помощью CSS свойств: уберем маркеры напротив каждого из пункта при помощи list-style none, преобразуем строчные теги гиперссылок в блочные, применив к ним правило display block, а также для разнообразия придадим каждой из них приятный фон.

Также нелишним будет задать отступы margin, чтобы еще более улучшить дизайн, немного отодвинув пункты меню друг от друга. Для вебстраниц сайта WordPress можно задать тегу UL class «menu», для которого указать необходимые стили в файле STYLE.CSS:

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

Разница с предыдущим вариантом разительная, не правда ли? Теперь мы получили картинку, которая гораздо больше напоминает классическое меню. Правда, пункты в нем расположены не горизонтально, а вертикально. Для полного решения задачи нужно дописать для элемента HTML списка LI свойство float left, полностью правило CSS для него станет таким:

В итоге менюшка превратиться в горизонтальный вариант:

Думаю, на основании выше предоставленной информации вам понятна причина, по которой произошла такая метаморфоза. Каждый вебэлемент меню с float left ориентируется на расположение контейнера, его границы и пытается занять место, сдвинувшись максимально вверх-влево. Так и случилось с блоком «Пункт 1», который расположился соответствующим образом.

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

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

В этом случае «Пункт 4» учитывает сначала верхнюю наиболее высоко расположенную границу и только затем смещается в крайнее левое положение, однако натыкается на самый первый вебэлемент. Ежели высота, скажем, третьего пункта, окажется большей, то картинка изменяется на следующую:

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

Если в практической верстке возникают подобные проблемы, то вместо CSS свойства float можно применить другие методы создания горизонтального меню. Однако, это уже отдельная тема, к которой мы обязательно обратимся в дальнейшем.

Эффект применения свойства clear (both, left, right)

Теперь посмотрим, как использовать на свое благо особенности плавающих элементов, но одновременно заставить ниже следующие блоки на вебстранице учитывать их положение и размеры. Этого можно добиться с помощью правила clear. Опять же всю информацию можно получить от первоисточника (консорциума W3C):

Правило CSS clear имеет четыре возможных значения, причем property none является параметром по умолчанию, что вполне естественно, поскольку в этом случае обеспечивается стандартный поток кода. Также clear (none, left, right, both) наследуется от родительского тега (inherit).

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

  • none — отменяет действие самого свойства clear, в результате содержание тега (например, текст) обтекает вэбэлемент в соответствии с заданными ему стилями в виде float;
  • left и right — ликвидирует обтекание соответственно с левого либо правого края;
  • both — препятствует обтеканию одновременно справа и слева. Это самый распространенное значение clear в практическом использовании.

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

Итак, возьмем два контейнера DIV, которые схематически могут представлять из себя 2 колонки. Пропишем для них CSS свойства, включая фиксированную ширину (width), цвет фона и превратив их в плавающие с помощью float left. Добавим к ним текст, заключенный в тег P, который, как известно, является строчным:

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

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

Опять же можете сами посмотреть вот здесь, как поведут себя все элементы, искусственно сужая-расширяя область просмотра. Чтобы устранить описанные недостатки, добавим контейнер со свойствами CSS и поместим внутрь его все имеющиеся слои. А также добавим дополнительно пустой DIV с правилом CSS clear both, чтобы запретить обтекание содержанием нижнего блока (текстом) колонок справа и слева:

Обратите внимание, что к стилям большого дива я добавил правило margin:0 auto, с помощью которого можно выровнять контейнер по центру. Результирующий вид будет таковым:

Теперь наша задача решена, поскольку итог соответствует поставленным условиям: две колонки расположены в горизонтальном ряду, а содержание ниже стоящего в коде вэбэлемента (ТЕКСТ) будет жестко оставаться на своем законном месте под колонками.

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

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL