
Это вторая статья из серии статей про магии размерностий и Котлина на примере библиотеки KotUniL.
В первой статье мы рассмотрели, как с помощью этой библиотеки не разбивать космические аппараты :-).
В этой статье мы рассмотрим менее очевидные, но не менее интересные фичи библиотеки.
Вот список всех статей серии:
Магия размерностей и магия Котлина. Часть первая: Введение в KotUniL
Магия размерностей и магия Котлина. Часть вторая: Продвинутые возможности KotUniL
Магия размерностей и магия Котлина. Часть третья: Смешение магий
Pretty print
Начнём мы с красивой распечатки результатов наших расчётов. В стандарте системы СИ на этот счёт есть строгие рекомендации, которые библиотека пытается в меру своих возможностей выполнять:
val s = 4.m * 5.m
assertEquals("20 m2", s.show("%.0f"))
val x = 20.l
val format = "%.2f"
assertEquals("0,02 m3", x.show(format))
val h = x/s
assertEquals("0,001 m", h.show("%.3f"))
val y = 3.1415927.m
assertEquals("3,142 m", y.show("%.3f"))Способы задания базовых единиц СИ
Как известно, система СИ определяет ровно 7 физических единиц, с помощью которых удаётся измерять и моделировать все объекты и процессы нашего мира.
Вот этот список:
SI Base Unit | Unit symbol |
|---|---|
second | s |
metre | m |
kilogram | kg |
ampere | A |
kelvin | K |
mole | mol |
candela | cd |
Рассмотрим, как можно задавать в KotUniL физические величины на примере одной секунды (равенства внизу показывают раз��ые способы физической величина “размером” в одну секунду):
s == 1*s
1*s == 1.0.s
Second(1.0) == 1.sПроизводные единицы СИ
Стандарт СИ определяет кроме семи базовых единиц также 22 производные единицы. Они перечислены в таблице ниже.
SI Derived Unit | Unit symbol | Formula |
|---|---|---|
radian | rad | m/m |
steradian | sr | m2/m2 |
hertz | Hz | 1/s |
newton | N | kgm/(s |
pascal | Pa | kg/(m * (s |
joule | J | kg(m2)/(s |
watt | W | kg*(m2)/(s |
coulomb | C | sA |
volt | V | kgm2*(s |
farad | F | (kg |
ohm | Ω | kgm2 * (s |
siemens | S | (kg |
weber | Wb | kg(m2) * (s |
tesla | T | kg* (s |
henry | H | kg* (m2)(s |
degreeCelsius | Celsius | (K |
lumen | lm | ((cd |
lux | lx | cdsr*(m |
becquerel | Bq | (s |
gray | Gy | (m2)(s |
sievert | Sv | (m2)(s |
katal | kat | (mol * (s |
Не удивляйтесь, если вы встретите в этой таблице и в библиотеке KotUniL необычные для идентификаторов символы типа Ω. Это возможно потому, что согласно спецификации в идентификаторах Kotlin могут использоваться самые распространенные символы юникода (см. параграф "1.2.4 Идентификаторы" в спецификации Kotlin). Производные единицы можно задавать и использовать так же, как и базовые. Переменных из обеих групп можно использовать в формулах путем умножения или деления.
Не удивляйтесь, когда увидите символ ^. В Котлине нет оператора для возведения в степень (взятия корня), но есть функция pow(a, b). KotUniL был расширен инфиксной функцией с той же семантикой. К сожалению, с помощью этого трюка нельзя установить правильный приоритет для этой функции. Хотя она выглядит как "настоящий" оператор, для сохранения правильного приоритета операции ее нужно заключить в круглые скобки.
Чтобы поближе разобраться с программированием производных единиц рассмотрим реальный пример.
Молодожёны Саша и Наташа решили выехать на природу. Они взяли с собой солнечную батарею. По приезду на место Саша сразу включили ее. Солнечная батарея работала 2 часа производила 12 вольт при 7 ампер. Выработанная электроэнергия хранилась в переносном аккумуляторе. Эффективность хранения составила 85%. После этого Наташа решила приготовить чай. Для приготовления горячей воды для чая с помощью чайника мощностью 500 ватт воду нужно кипятить 8 минут. Вопрос, достаточно ли для этого накопленной в аккумуляторе электроэнергии?
Напишем простенький код с использованием KotUniL:
val producedElectricity = 12.V * 7.A * 2.h
val savedElectricity = producedElectricity * 85.`%`
val neededElectricity = 0.5.kW * 8.min
val dif = savedElectricity - neededElectricity
assertTrue(dif < 0.W*h) //Сравнение единиц KotUniL
assertTrue(dif.value < 0) //Сравнение безразмерных величинОбратите внимание, что для удобства мы используем здесь символ %. Это также является расширением Kotlin в нашей библиотеке.
Что касается этого и ряда других подобных расширений, рассмотрим цитату из спецификации: "Kotlin поддерживает способ задания идентификаторов, заключая любую последовательность символов в символы обратного знака (`), что позволяет использовать любое имя в качестве идентификатора." (См. параграф 1.2.4 "Идентификаторы" в спецификации Kotlin).
Очень важно: символ backtick (`) (UTF-8 код U+0060) не равен символам апострофа на клавиатуре (UTF-8 код U+0027). Если его нет на вашей клавиатуре, с��опируйте его непосредственно из этого примера.
Большинство производных единиц могут быть получены из базовых единиц или из других производных единиц различными способами.
Рассмотрим пример Tesla:
assertEquals(T, kg * (s `^` -2) * (A `^` -1))
assertEquals(T, Wb/m2)Собственные производные единицы
С помощью KotUniL вы можете определить свои собственные производные единицы.
Рассмотрим не вполне научно обоснованный пример. Представим, что скорость таяния снега в горах пропорциональна продолжительности и температуре выше 0 °C и равняется 10 микрон в час на градус. Это будет наша новая производная единица. Если текущая толщина снега составляет 10 см, то какая его часть растает за 5 часов при температуре 20 °C?
Приведенный ниже код также демонстрирует приятную сторону Kotlin - возможность использования символов Unicode, например, греческих букв.
val ζ = 10.μm/(h*K) //скорость таяния льда
val τ = 10.cm
val t = 20.`°C`
val ξ = 5.h*(t - 0.`°C`)
val σ = ζ*ξ //уровень стаявшего снега
val α = σ/τ //отношения стаявшего снега к исходному
assertEquals(1.0, α.`as %`, ε) // Представление отношения в процентахОбратите внимание, как можно представить результат расчета в процентах: α.`as %`- отношение, представленное в процентах.
ε - некоторое небольшое значение для допуска при сравнении двойных чисел. Это тоже одна из определённых в KotUniL переменных.
Префиксы системы СИ
Система СИ определяет префиксы, которые мы с детства привыкли употреблять, часто не задумываясь. Размеры комнаты мы измеряем в “чистых” метрах, размеры смартфонов в миллиметрах а расстояния между городами в километрах.
В зависимости от предметного домена часто удобно работать не с чистыми, а с префиксами единицами. Каждый префикс имеет своё имя и сокращённое обозначение в виде символа.
В KotUniL реализованы все предусмотренные стандартом Си префиксы. Вот их полная таблица.
Prefix | Symbol | Degree |
|---|---|---|
quetta | Q | 30 |
ronna | R | 27 |
yotta | Y | 24 |
zetta | Z | 21 |
exa | E | 18 |
peta | P | 15 |
tera | T | 12 |
giga | G | 9 |
mega | M | 6 |
kilo | k | 3 |
hecto | h | 2 |
deca | da | 1 |
deci | d | -1 |
centi | c | -2 |
milli | m | -3 |
micro | μ | -6 |
nano | n | -9 |
pico | p | -12 |
femto | f | -15 |
atto | a | -18 |
zepto | z | -21 |
yocto | y | -24 |
ronto | r | -27 |
quecto | q | -30 |
В приведенном ниже примере мы проверяем, что один километр равен миллиарду микрометров.
val d = km - (10 `^` 9) * μm
assertTrue(abs(d.value) < ε)Нестандартные единицы
Стандарт СИ признаёт в качестве допустимых ряд единиц, которые исторически отвоевали себе место в практической деятельности людей, такие как минуты, часы и дни для времени, квадратные и кубические метры и т.д.
Таблица внизу даёт представление об этих величинах.
Name | Symbol | Derived quantity |
|---|---|---|
m2 | ||
m3 | ||
m/s | ||
m/s2 | ||
m−1 | ||
kg/m3 | ||
kilogram per square metre | kg/m2 | |
cubic metre per kilogram | m3/kg | |
ampere per square metre | A/m2 | |
A/m | ||
mole per cubic metre | mol/m3 | |
kg/m3 | ||
cd/m2 |
Пример:
Городской парк имеет площадь 2.35 га. Во время дождя с неба выпало 1 мм воды.
Если бы дождя не было, парк нужно было ��ы поливать водой из автомобильных цистерн. Одна автомобильная цистерна вмещает 4 тонны воды. Сколько цистерн необходимо для достижения того же эффекта, что и в случае дождя? Напоминание: плотность воды составляет 1 кг/л
val s = 2.35ha
val ω = s*1.mm // Суммарный объём упавшей с неба воды
val ρ = kg/l // Плотность воды
val τ = ω * ρ // Общий вес дождевой воды
val n = τ/4.t
assertEquals(5.875, n.value, ε)Добавляем валюты
Чтобы расширить сферу применения библиотеки, в неё наряду с физическими единицами в качестве самостоятельных единиц добавлены тридцать самых популярных валют мира.
Вот этот список
UnitedStatesDollar, USD, US$, United States dollar
Euro, EUR, €, Euro
JapaneseYen, JPY, ¥, Japanese yen
PoundSterling, GBP, £, Sterling
Renminbi, CNY, 人民币, Renminbi
AustralianDollar, AUD, A$, Australian dollar
CanadianDollar, CAD, C$, Canadian dollar
SwissFranc, CHF, SCHF, Swiss franc //To avoid name conflict for CHF
HongKongDollar, HKD, HK$, Hong Kong dollar
SingaporeDollar, SGD, S$, Singapore dollar
SwedishKrona, SEK, skr, Swedish krona //To avoid name conflict for symbol 'kr'
SouthKoreanWon, KRW, ₩, South Korean won
NorwegianKrone, NOK, nkr, Norwegian krone //To avoid name conflict for symbol 'kr'
NewZealandDollar, NZD, NZ$, New Zealand dollar
IndianRupee, INR, ₹, Indian rupee
MexicanPeso, MXN, $, Mexican peso
NewTaiwanDollar, TWD, NT$, New Taiwan dollar
SouthAfricanRand, ZAR, R, South African rand
BrazilianReal, BRL, R$, Brazilian real
DanishKrone, DKK, dkr, Danish krone //To avoid name conflict for symbol 'kr'
PolishZłoty, PLN, zł, Polish złoty
ThaiBaht, THB, ฿, Thai bahtIsraeli
NewShekel, ILS, ₪ Israeli new shekel
IndonesianRupiah, IDR, Rp, Indonesian rupiah
CzechKoruna, CZK, Kč, Czech koruna
UAEDirham, AED, Dh, UAE dirham
TurkishLira, TRY, ₺, Turkish lira
HungarianForint, HUF, Ft, Hungarian forint
ChileanPeso, CLP, CLP﷼ , Saudi riyal
PhilippinePeso, PHP, ₱, Philippine peso
MalaysianRinggit, MYR, RM, Malaysian ringgit
ColombianPeso, COP, COL, Colombian peso
RussianRuble, RUB, ₽, Russian ruble
RomanianLeu, RON, L, Romanian leu
И снова, уже последний пример:
Владелец дома Вова решил покрыть пол плиткой в одной из своих комнат.
Он купил 16,5 кв. м плитки по цене 52 €/кв. м. Сколько он заплатил за плитку?
val prise = 52.`€`/m2
val s = 16.5*m2
val cost = s*prise
assertEquals("858,00 EUR", cost.show("%.2f"))
assertEquals("EUR", cost.unitSymbols())Ну вот мы и познакомились с продвинутыми фичами библиотеки KotUniL.
Напомню, что способ её подключения в ваш проект описан в предыдущей статье серии.
В следующей, последней статье серии я попытаюсь рассказать о некоторых поразивших меня “магических” особенностях системы СИ и их влиянии на дизайн библиотеки.
Иллюстрация: Система основных измерений в физике, основанная на математическом манипулировании длиной, временем и массой. Источник: Wikipedia
