
Это вторая статья из серии статей про магии размерностий и Котлина на примере библиотеки 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,3 га. Во время дождя с неба выпало 1 мм воды.
Если бы дождя не было, парк нужно было бы поливать водой из автомобильных цистерн. Одна автомобильная цистерна вмещает 4 тонны воды. Сколько цистерн необходимо для достижения того же эффекта, что и в случае дождя? Напоминание: плотность воды составляет 1 кг/л
val s = 1.ha val ω = s*100.mm // Суммарный объём упавшей с неба воды val ρ = kg/l // Плотность воды val τ = ω * ρ // Общий вес дождевой воды val n = τ/4.t assertEquals(250.0, n.value, ε)
Добавляем валюты
Чтобы расширить сферу применения библиотеки, в неё наряду с физическими единицами в качестве самостоятельных единиц добавлены тридцать самых популярных валют мира.
Вот этот список:
UnitedStatesDollar, USD, US$, United States dollarEuro,
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, ฿</span>, Thai bahtIsraeliNewShekel, ILS, ₪,
Israeli new shekelIndonesianRupiah, 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$, Chilean peso
SaudiRiyal, SAR, ﷼ , 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
ссылка на оригинал статьи https://habr.com/ru/post/705788/
Добавить комментарий