seg — тип данных для отрезков или интервалов с плавающей точкой
Эта страница переведена при помощи нейросети GigaChat.
Модуль добавляет тип данных seg
, предназначенный для хранения отрезков или диапазонов чисел с плавающей точкой. Тип seg
позволяет учитывать погрешность значений границ интервала, что удобно для обработки результатов научных экспериментов и исследований.
Модуль сертифицирован как безопасный («trusted»), значит любой пользователь с правом создавать объекты (CREATE
) в текущей базе данных сможет установить этот модуль самостоятельно.
Рациональность
Измерения отличаются большей геометрической сложностью, нежели простая точка на числовой прямой. Как правило, они представляют собой участки числового континуума с относительно размытыми границами. Это связано с наличием неопределенностей и случайных факторов, а также с природой самой величины, которая может изначально являться интервалом, выражающим определенное состояние или условие, например диапазон стабильных температур для конкретного белка.
Исходя из интуитивных соображений, хранение подобных данных в форме интервалов представляется предпочтительным вариантом по сравнению с использованием пары конкретных чисел. Опыт показывает, что такой способ действительно оказывается наиболее практичным решением для большинства приложений.
Более того, очевидно, что размытые границы означают частичную утрату информации при применении стандартных числовых форматов. Чтобы убедиться в этом, рассмотрим следующую ситуацию: инструмент фиксирует значение 6,50, и это значение записывается в базу данных. Что произойдет при последующем извлечении данной записи:
test=> select 6.50 :: float8 as "pH";
pH
---
6.5
(1 row)
Значение 6,50 в метрологии отличается от 6,5. Разница бывает принципиально важной. Исследователи традиционно указывают ровно столько значащих цифр, насколько уверены в точности результата. Число 6,50 фактически описывает менее четко очерченный интервал, вложенный внутрь еще более широкого и расплывчатого интервала 6,5. Единственная общая черта обоих интервалов — совпадение центральных точек.
Очевидно, что столь различные по информативности и точности данные недопустимо отображать идентично.
Поэтому целесообразно ввести особый тип данных, позволяющий указывать границу интервала с произвольной степенью детализации. Здесь важно подчеркнуть, что степень точности должна индивидуально устанавливаться каждым элементом данных отдельно.
Для лучшего понимания взгляните на следующий пример:
test=> select '6.25 .. 6.50'::seg as "pH";
pH
------------
6.25 .. 6.50
(1 row)
Синтаксис
Внешнее представление интервала формируется с использованием одного или двух чисел с плавающей запятой, объединенных оператором диапазона (..
или ...
). В качестве альтернативы его можно указать как центральную точку плюс-минус отклонение. Также могут быть сохранены необязательные индикаторы достоверности (<
, >
или ~
). (Однако встроенные операторы игнорируют индикаторы достоверности.) Таблица «Внешнее представление seg
» дает обзор разрешенных представлений; таблица «Примеры допустимого ввода seg
» показывает некоторые примеры.
В Таблице «Внешнее представление seg
», x
, y
и delta
обозначают числа с плавающей запятой. x
и y
, но не delta
, могут предшествовать индикатор достоверности.
Таблица «Внешнее представление seg
»
x | Единичное значение (интервал нулевой длины) |
x .. y | Интервал от x до y |
x (+-) delta | Интервал от x - delta до x + delta |
x .. | Открытый интервал с нижней границей x |
.. x | Открытый интервал с верхней границей x |
Таблица «Примеры допустимого ввода seg
»
5.0 | Создает сегмент нулевой длины (точку, если хотите) |
~5.0 | Создает сегмент нулевой длины и записывает ~ в данные. ~ игнорируется операциями seg , но сохраняется как комментарий. |
<5.0 | Создает точку на отметке 5.0. < игнорируется, но сохраняется как комментарий. |
>5.0 | Создает точку на отметке 5.0. > игнорируется, но сохраняется как комментарий. |
5(+-)0.3 | Создает интервал 4.7 .. 5.3 . Обратите внимание, что нотация (+-) не сохраняется. |
50 .. | Все, что больше или равно 50 |
.. 0 | Все, что меньше или равно 0 |
1.5e-2 .. 2E-2 | Создает интервал 0.015 .. 0.02 |
1 ... 2 | То же самое, что и 1...2 , или 1 .. 2 , или 1..2 (пробелы вокруг оператора диапазона игнорируются) |
Поскольку оператор ...
широко используется в источниках данных, он допускается в качестве альтернативного написания оператора ..
. К сожалению, это создает двусмысленность при синтаксическом анализе: неясно, должна ли верхняя граница в 0...23
быть 23
или 0.23
. Это решается путем требования наличия хотя бы одной цифры перед десятичной точкой во всех числах в seg
вводе.
В целях проверки здравого смысла seg
отклоняет интервалы с нижней границей большей, чем верхняя, например 5 .. 2
.
Точность
Данные сохраняются в виде пары 32-разрядных вещественных чисел. Таким образом, числа, содержащие больше 7 значимых цифр, подвергаются округлению.
Числа, состоящие из 7 и меньшего количества значащих цифр, остаются неизмененными и сохраняют исходную точность. К примеру, если возвращается значение 0,00, можно уверенно утверждать, что последующие нули не вызваны особенностями формата вывода, а точно соответствуют уровню точности входных данных. Ведущие нули не влияют на количество значащих цифр: значение 0,0067 учитывается как имеющее две значащие цифры.
Использование
Этот модуль включает класс операторов индекса GiST для значений seg
. Операторы, поддерживаемые классом операторов GiST, показаны в таблице «Операторы сегментов GiST».
Таблица «Операторы сегментов GiST»:
Оператор | Описание |
---|---|
seg << seg → boolean | Полностью ли первое seg находится слева от второго? [a, b] << [c, d] истинно, если b < c . |
seg >> seg → boolean | Полностью ли первое seg находится справа от второго? [a, b] >> [c, d] истинно, если a > d . |
seg &< seg → boolean | Разве первое seg не простирается вправо от второго? [a, b] &< [c, d] истинно, если b <= d . |
seg &> seg → boolean | Не расширяется ли первое seg влево от второго? [a, b] &> [c, d] истинно, если a >= c . |
seg = seg → boolean | Равны ли два seg ? |
seg && seg → boolean | Перекрываются ли два seg ? |
seg @> seg → boolean | Содержит ли первое seg второе? |
seg <@ seg → boolean | Является ли первое seg содержимым второго? |
Эти операторы сначала сравнивают (а) с (с), и если они равны, сравнивают (b) с (d). Это приводит к достаточно хорошей сортировке в большинстве случаев, что полезно, если хотите использовать ORDER BY
с этим типом.
Примечания
Примеры использования механизма преобразования можно посмотреть в файле регрессионного теста sql/seg.sql
.
Важно отметить, что механизм перевода формата (+-)
в обычный диапазон не всегда точно определяет количество значащих цифр для границы интервала. Например, если вычисленный интервал включает степень числа десять, к нижней границе добавляется лишняя цифра.
postgres=> select '10(+-)1'::seg as seg;
seg
---------
9.0 .. 11 -- should be: 9 .. 11
Производительность индекса R-дерева может во многом зависеть от первоначального порядка входных значений. Может быть очень полезно отсортировать входную таблицу по столбцу seg
; смотрите сценарий sort-segments.pl
для примера.