?

Log in

No account? Create an account

Домашний интернет для чайников, часть 1
ilyachalov
Чайник (кто это) в этом вопросе — это я. Пост не про все случаи жизни, а про конкретный мой интернет.

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

От телефонного аппарата имеется телефонный шнур (или кабель, или удлинитель) с разъемом RJ-11. От компьютера — кабель локальной сети с разъемом RJ-45 (подробнее про эти разъемы).


слева, который поменьше, это RJ-11, справа — RJ-45

Там, где телефонный распределительный провод подходит к телефону, оборудована розетка, представляющая собой небольшую прямоугольную коробочку со съемной крышкой. Коробочка приклеивается (или прикрепляется другим образом) к стене. С одной стороны в ней небольшое отверстие для входа провода, с другой — гнездо, куда втыкается разъем RJ-11 от телефона.

на фотографии — две розетки RJ-11, можно осмотреть с обеих сторон

У меня два договора с провайдером — на телефонную связь и на интернет по технологии ADSL. Плюс этой технологии в том, что интернет поставляется по той же телефонной линии, которую использует телефон, причем использование телефона и интернета может происходить одновременно. Технология ADSL заменила наш родной коммутируемый доступ (он же «диалап»), переведя скорости обмена данными с килобит в секунду на мегабиты в секунду.

Всё же для нормальной совместной работы интернета по технологии ADSL и телефонной связи требуется специальное устройство, которое называется сплиттером (синонимы: «частотный разделитель», «ADSL-фильтр», «ADSL-splitter»). У меня сплиттер представляет собой примерно такого же размера коробочку, как вышеописанная розетка RJ-11, только без съемной крышки. Но в отличие от нее сплиттер имеет одно гнездо для разъема RJ-11 (обозначенное словом «Line») с одной стороны и два гнезда для разъема RJ-11 с другой стороны (обозначаются как «Modem» и «Phone»).


ADSL-сплиттер

В гнездо «Линия» должен быть включен телефонный кабель из вышеописанной розетки RJ-11, в которую ранее был введен телефонный распределительный провод. Из гнезд «Модем» и «Телефон», соответственно, должны выходить телефонные кабели к модему и телефонному аппарату.

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

Также я сначала наивно считал, что розетка под разъем RJ-11 — это и есть сплиттер.

Продолжение следует...

Функции арктангенса atan и atan2 в C++
ilyachalov
В предыдущем посте о связи прямоугольных и полярных координат в частности выведены формулы для перевода прямоугольных координат в полярные:

r = sqrt(x * x + y * y);
фи = atan(y / x);

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

Формула для вычисления угла фи выведена из геометрического определения тангенса угла

tan(фи) = y / x;

Изобразим график функции z = tan(фи), где z = y / x:

График функции z = tan(фи)

Вспомним, что график обратной функции (в нашем случае арктангенса по отношению к тангенсу) можно получить, повернув исходный график влево на 90 градусов и отразив полученное зеркально слева направо. Итак, график функции фи = atan(z):

График функции фи = atan(z)

Получилось, что в случае функции фи = atan(z) для одной и той же области определения (значения на оси z) существует множество областей значений (значения на оси фи).

Например, для графика, проходящего через начало координат (z = 0, фи = 0) область значений находится в пределах от –PI/2 до PI/2. Этот график обычно и обозначают формулой фи = atan(z), уточняя рядом с формулой область значений. Графики, лежащие выше и ниже этого графика, обозначают, прибавляя или отнимая от исходной формулы число Пи. Например, для нескольких графиков, лежащих ближе к началу координат:
...
фи = atan(z) + 2 * PI,  3*PI/2 < фи < 5*PI/2;
фи = atan(z) + PI,        PI/2 < фи < 3*PI/2;
фи = atan(z),            –PI/2 < фи < PI/2;
фи = atan(z) – PI,     –3*PI/2 < фи < –PI/2;
фи = atan(z) – 2 * PI, –5*PI/2 < фи < –3*PI/2;
...

Определенная в стандарте языка C++ функция для вычисления арктангенса atan является отображением графика фи = atan(z), проходящего через начало координат, то есть она возвращает значения в пределах от –PI/2 до PI/2.

Теперь вернемся к рисунку с полярными координатами в начале этого поста. И увидим, что, воспользовавшись стандартной функцией atan в языке C++ при попытке перевода прямоугольных координат в полярные, мы сможем получить угол фи только для 1-го и 4-го квадрантов системы координат (про квадранты я писал в посте о системах координат) из-за вышеописанного ограничения возвращаемых функцией atan значений пределами от –PI/2 до PI/2.

Что же делать? Воспользуемся кусочками других графиков арктангенса, о которых писалось выше. Вот как нужные кусочки графиков будут выглядеть на рисунке:

Кусочки графиков арктангенса

То есть для реализации этого в программе на C++ через стандартную функцию atan нужно будет описать нахождение угла фи с помощью следующих равенств:

(1 и 4 квадранты) если (x > 0), то фи = atan(y / x); красный график
(2 квадрант) если (x < 0 и y > 0), то фи = atan(y / x) + PI; зеленый
(3 квадрант) если (x < 0 и y < 0), то фи = atan(y / x) – PI; синий

Однако, вместо этого в программе на C++ можно использовать стандартную функцию нахождения арктангенса atan2, которая заменяет все вышеперечисленные равенства и выдает угол фи в нужных пределах от –PI до PI. То есть для перевода прямоугольных координат в полярные нужно использовать следующие формулы:

r = sqrt(x * x + y * y);
фи = atan2(y / x);


Если стандартная функция atan принимает один аргумент, то стандартная функция atan2 принимает два аргумента — прямоугольные координаты y и x (именно в таком порядке) и в зависимости от знаков каждого из аргументов выдает нужный график с нужным результатом:
radius = sqrt(x * x + y * y);
angle = atan2(y, x);

Подводящие к этому посты:
1. Мера измерения углов, радианы и градусы (тут).
2. Число Пи в программе на C++ (тут).
3. Прямоугольная и полярная системы координат (тут).
4. Связь прямоугольных и полярных координат (тут).

Связь прямоугольных и полярных координат
ilyachalov
Про прямоугольную и полярную системы координат рассказано в предыдущем посте.

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

Если считать полюс началом и прямоугольной системы координат, то у нас получился прямоугольный треугольник, в котором радиус r является гипотенузой, а катеты равны координатам x и y нашей точки в прямоугольной системе координат.

Исходя из теоремы Пифагора, получим

r * r = x * x + y * y;
r = sqrt(x * x + y * y);
формула 1

Вспомнив, что синус угла равен отношению противолежащего катета к гипотенузе, а косинус угла — отношению прилежащего катета к гипотенузе, получим

sin(фи) = y / r;
cos(фи) = x / r;


y = r * sin(фи); формула 2
x = r * cos(фи); формула 3

С помощью формул 2 и 3 осуществляется перевод полярных координат в прямоугольные.

Теперь вспомним, что тангенс угла равен отношению противолежащего катета к прилежащему.

tan(фи) = y / x;
фи = atan(y / x);
формула 4

Под tan и atan здесь подразумеваются соответственно тангенс и арктангенс. С помощью формул 1 и 4 осуществляется перевод прямоугольных координат в полярные.

В следующем посте рассказано, почему с формулой 4 всё не так просто и зачем в языке C++ для вычисления арктангенса есть две функции — atan и atan2.

Прямоугольная и полярная системы координат
ilyachalov
Системы координат используются для ориентации в пространстве или на плоскости. Тут я хотел бы рассмотреть две системы координат на плоскости.

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

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

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

Горизонтальный луч, отходящий от полюса вправо, называется полярной осью, от этой оси отсчитывается угол фи. Угол может отсчитываться двумя способами. Первый способ продемонстрирован на рисунке выше этого абзаца: угол отсчитывается от полярной оси против часовой стрелки в пределах от 0 до 2 * PI радиан.

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

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

Число Пи в программе на C++
ilyachalov
Как определить число Пи в программе на языке C++? Стандартом языка эта константа не определена (но, возможно, появится в будущем).

Первая мысль — создать константу одного из вещественных типов. Сколько знаков после запятой нужно прописать? В стандарте языка определен класс-шаблон numeric_limits, с помощью которого можно узнать ограничения в том числе и вещественных типов языка. К примеру, значение std::numeric_limits<T>::digits10 возвращает количество десятичных цифр, которое тип может представлять без потери точности.

https://en.cppreference.com/w/cpp/types/numeric_limits/digits10

На сегодня для типа float это 6, для типа double это 15, а для типа long double это 18. Последнее верно, только если long double имеет 80-битное представление. К примеру, в случае компилятора среды «Visual Studio Community 2017» для типа long double обсуждаемое количество равно 15, как и для типа double (источник), так как в этой системе тип long double имеет 64-битное представление и по сути является аналогом типа double.

Итак, первый способ определения числа Пи:
const double PI = 3.141592653589793; // 15 знаков после точки
Строго говоря, в этой константе десятичных цифр 16 (одна до точки, 15 — после), но на практике (компилятор среды «Visual Studio Community 2017») именно в таком виде константа без потерь проходит, к примеру, цепочку преобразований «текст → double → текст». Если добавить, например, 16-ю цифру после точки, то после указанного преобразования она уже не сохранится.

Возможно, имеется какой-то практический смысл в том, чтобы указывать в обсуждаемой константе больше 15 цифр после запятой. Потому что в среде «Visual Studio Community 2017» определена константа M_PI, содержащая значение 3.14159265358979323846 (20 знаков после точки). Источник.

Итак, второй способ определения числа Пи — использование константы M_PI (требуется определение _USE_MATH_DEFINES и подключение соответствующего заголовочного файла):
#define _USE_MATH_DEFINES // для C++
#include <cmath>
Константа M_PI определена в одном из стандартных заголовочных файлов с помощью директивы компилятору #define M_PI 3.14159265358979323846.

Третий способ определения числа Пи — с помощью одной из обратных тригонометрических функций. Например, с помощью арккосинуса:
const double PI = acos(-1.0);

Ну и на сладкое. Получение числа Пи с помощью ассемблерной вставки (отсюда):
double get_PI()
{
    double pi;
    __asm
    {
        fldpi
        fstp pi
    }
    return pi;
}

double PI = get_PI();

Всё перечисленное проверено на «Windows 7 Профессиональная» (SP1), 64-разрядная. Компилятор среды «Visual Studio Community 2017».

Мера измерения углов, радианы и градусы
ilyachalov
Радиан (как и градусы) является мерой для измерения углов. Как определили угол в 1 радиан? Представим себе угол, вершина которого лежит в центре окружности (такой угол называют центральным). Стороны такого угла являются радиусами этой окружности. Итак, угол в 1 радиан — это центральный угол, длина дуги которого равна его стороне (а значит и радиусу окружности). Википедия.

Проще говоря, мерой для измерения любого центрального угла сделали отношение его дуги к его стороне (радиусу окружности). Например, прямоугольный угол (90 градусов) равен отношению четверти длины окружности к радиусу радиан. Угол в 180 градусов равен отношению половинки длины окружности к радиусу радиан. Угол в 360 градусов равен отношению длины окружности к радиусу радиан. Вспомним теперь, что отношение длины окружности к ее диаметру равно числу Пи. Поэтому для выражения меры углов в радианах часто применяют число Пи (PI).

360 градусов = (длина P окружности / ее радиус R) радиан;
PI = длина P окружности / ее диаметр D;
PI = P / (2 * R);
PI * 2 = P / R;
360 градусов = (P / R) радиан = 2 * PI радиан;
180 градусов = PI радиан;
90 градусов = (PI / 2) радиан;

Отсюда легко вывести формулы для перевода радианов в градусы и обратно. Предположим, что Nrad — мера угла в радианах, а Ngra — мера угла в градусах. Тогда

Nrad = Ngra * PI / 180;
Ngra = Nrad * 180 / PI;

Microsoft Edge для Windows 7
ilyachalov
Наконец-то здравый смысл начинает побеждать. Компания Microsoft анонсировала новость о том, что следующая версия ее браузера Microsoft Edge станет доступна на операционной системе Windows 7.

Краткое содержание предыдущих серий. В 2015 году пользователи операционных систем Microsoft Windows ожидали выхода новой версии браузера Internet Explorer (кратко — IE), последняя версия которого на тот момент была 11 (кратко — IE11). И эта версия вышла одновременно с появлением новой версии операционной системы Windows — Windows 10. Новую версию браузера назвали не IE12, как ожидалось, а Microsoft Edge. Но важным было не это, а факт, что Microsoft Edge работал отныне только на новой Windows 10, а пользователям Windows 7 и Windows 8 оставалось лишь либо перейти на новую версию операционной системы, либо... сосать лапу, ведь поддерживать IE11 никто не собирался.

Конечно, пользователи «устаревших» операционных систем Windows (в число которых вхожу и я) не пропали. Довольно большую часть пользователей, ставших внезапно ненужными компании Microsoft, с радостью подхватили создатели альтернативных браузеров, очумевшие от такого неожиданного подарка. Лично я, как, по-видимому, и большинство моих коллег по несчастью, перешел на Google Chrome (кратко — Хром), который хоть и обладает негибким к настройке интерфейсом, но работает со всеми, кто попадется под руку, даже и с владельцами «неправильных» операционных систем.

Минутка статистики. Источники:
https://www.w3schools.com/browsers/
https://www.w3schools.com/browsers/browsers_os.asp

В 1-м полугодии 2015 г. IE использовался в среднем 7,62 % пользователей. В 1-м полугодии 2019 г. IE или Edge использовались в среднем 3,77 % пользователей. Как сказал чукча в известном анекдоте: «Однако, тенденция!» Для Хрома средние цифры за те же периоды следующие: от 63,62 % до 80,1 %.

В это же время статистика по операционным системам следующая. В августе 2015 г.: Win10 — 3.5 % от общего числа пользователей, Win8 — 19,4 %, Win7 — 47,2 %. В июле 2019 г.: Win10 — 52,7 %, Win8 — 5,9 %, Win7 — 15,0 %.

Чукчи из руководства Microsoft прохлопали за четыре года половину пользователей своего браузера из тех, которые еще продолжали пользоваться IE или Edge. И это несмотря на то, что количество пользователей их операционных систем оставалось примерно на том же уровне. Я думаю, это произошло не в последнюю очередь из-за вышеописанной попытки кидка с браузерами.

В начале декабря 2018 г. в Microsoft поняли, что проиграли в очередном витке войны браузеров и решили похоронить свои разработки по Microsoft Edge. Новая версия этого браузера в составе Windows 10 будет основана на веб-браузере с открытым исходным кодом Chromium (не путать с Google Chrome, который тоже основан на Chromium). Заодно в Microsoft заявили, что новая версия Microsoft Edge наконец станет доступна и на Windows 8 с Windows 7. Источник.

В апреле 2019 г. стала доступной черновая версия Microsoft Edge на базе Chromium. С июня 2019 г. она доступна для Windows 8 и Windows 7. Создан специальный сайт (там есть и русская версия):

https://www.microsoftedgeinsider.com

С него можно скачать черновую версию Microsoft Edge на базе Chromium (ее почему-то называют «Dev Channel», но не суть), что я и сделал для своей Windows 7.

Браузером уже можно спокойно пользоваться. При установке он копирует закладки из IE11.

Times = умножить
ilyachalov
Сначала перевод учебника Лафоре на русский показался мне неплохим. Но чем сложнее становится материал, тем больше я нахожу ошибок и тем они грубее. Первые шесть глав еще можно читать, седьмая-восьмая и далее — только с постоянным заглядыванием в оригинал.

Цитата (стр.357):

bМоnеу = bMoney * long double (цена за единицу времени, затраченного на изделие)


Оригинал (стр.368):

bMoney = bMoney * long double (price per widget times number of widgets)


Должно быть:

bМоnеу = bMoney * long double (цена изделия умножается на количество изделий)


В данном контексте слово «times» переводится как «умножить», а не как «время». В этом можно убедиться на сайте Кембриджского англо-русского словаря:

https://dictionary.cambridge.org/ru/словарь/англо-русский/times

Интересно, как эти горе-переводчики перевели бы словосочетание «times table»? Таблица времени?

Порядок действий в выражениях
ilyachalov
Приехали. «Старость — не радость, маразм — не оргазм» (Игорь Губерман).

Забыл порядок действий в арифметических выражениях. Правда, я такой далеко не один.

https://news.mail.ru/society/38199895/

Цитата:

Пример из школьной программы по математике «8:2(2+2)=?» был опубликован в твиттере. Большинство пользователей не смогли ответить на него правильно.


Что сначала нужно посчитать в скобках, это я помнил. Также помнил, что умножение и деление имеют приоритет перед сложением и вычитанием.

А вот то, что если операции одного приоритета (одной ступени), то расчет ведется слева направо, забыл.

И действительно:

8 : 2 * 4 ≠ 1 (расчет справа налево, неверно!)
8 : 2 * 4 = 16 (расчет слева направо, верно)

Кстати, симпатичный сайт «Математика с нуля»: http://spacemath.xyz/
Про порядок действий в выражениях: http://spacemath.xyz/poryadok_deistviy/

Некоторые особенности типа int в C++
ilyachalov
Операционная система: «Windows 7 Профессиональная» (SP1), 64-разрядная. Компилятор среды «Visual Studio Community 2017».

int — основной в языке тип целого числа со знаком. signed int — синоним int.

В 8-разрядных и 16-разрядных системах int занимал 2 байта, в современных 32- и 64-разрядных системах занимает обычно 4 байта. Предполагая, что в байте 8 бит (существуют системы, в которых в байте другое количество бит), получаем, что 4 байта — это 32 бита.

Если в программе мы работаем только с положительными целыми числами, то можно использовать тип unsigned int (целое без знака). При этом в 4 байта можно поместить 2^n (два в степени n) значений, где n = 32 (количество разрядов или битов). Из-за того, что в диапазон представляемых значений необходимо включить число 0 (ноль), диапазон представляемых типом unsigned int значений будет не 0..2^n, как можно было бы подумать, а

0..(2^n - 1)
или 0..(2^32 - 1)
или 0..(4'294'967'296 - 1)
или 0..4'294'967'295

(границы входят в диапазон представляемых значений)

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

Самый старший бит (тот, который находится слева) отводится для хранения знака числа (0 — число положительное, 1 — число отрицательное). Значит, у нас остается для представления чисел 31 бит: 31 бит для отрицательных чисел и 31 бит для положительных чисел. То есть мы можем представить с помощью типа int 2^(n-1) отрицательных чисел и 2^(n-1) положительных чисел (n = 32, как мы помним). Однако, как и для типа unsigned int, для типа int требуется куда-то включить число 0 (ноль). Его включают в положительные числа, хотя оно, как мы помним из математики, не является ни положительным, ни отрицательным. Исходя из этого, диапазон представляемых типом int отрицательных чисел будет -2^(n-1)..-1, а диапазон представляемых типом int положительных чисел будет 0..2^(n-1)-1, то есть

-2^(n-1)..-1 и 0..2^(n-1)-1
или -2^(n-1)..2^(n-1)-1
или -2^(32-1)..2^(32-1)-1
или -2^31..2^31-1
или -2'147'483'648..2'147'483'648-1
или -2'147'483'648..2'147'483'647

(границы входят в диапазон представляемых значений)

Вот почему компилятор позволяет такой диапазон представляемых типом int значений, несмотря на то, что в стандарте языка Си установлен диапазон значений, определяемый по формуле -(2^(n-1)-1)..2^(n-1)-1, то есть

-2'147'483'647..2'147'483'647 (согласно стандарта)
-2'147'483'648..2'147'483'647 (фактическая реализация)

Кстати, в тексте программ позволяется использовать апострофы в качестве разделителей прямо в числовых литералах, что, по-моему, очень удобно. Например:
int a = 2147483647;
int b = 2'147'483'647;

Перейдем к интересным неочевидным штукам. Например, в результате выражения
int b = 2'147'483'648;
переменной b присваивается не указанное значение, а это же значение, только со знаком минус: -2'147'483'648. Это происходит потому, что значение справа от знака присваивания считается компилятором значением типа unsigned long, а не значением типа int (как должно быть по умолчанию для числового литерала), так как оно выходит за рамки диапазона представляемых типом int значений. Далее компилятор пытается записать в переменную типа int значение, которое туда не может поместиться, и бит значения числа записывается в самый старший бит, который предназначен для хранения знака числа, а не битов значения числа.

Еще один казус. Попытка использовать числовой литерал с наименьшим возможным для типа int значением -2'147'483'648 приведет к ошибке C4146:
int b = -2'147'483'648;

Почему это происходит? Потому что компилятор не включает знак минуса в понятие числового литерала, то есть сначала рассматривается значение 2'147'483'648, которое не может быть значением типа int, как уже указывалось выше, и считается значением типа unsigned long (целое без знака). После этого компилятор пытается применить унарную операцию отрицания к целому без знака, которое не может быть отрицательным, что логично является ошибкой.

Что делать? Рекомендуется применять вместо значения -2'147'483'648 встроенную константу INT_MIN с этим значением, определенную в заголовочном файле limits.h, либо писать вот так:
int b = -2'147'483'647 - 1;