Перейти к основному содержимому

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 << segbooleanПолностью ли первое seg находится слева от второго? [a, b] << [c, d] истинно, если b < c.
seg >> segbooleanПолностью ли первое seg находится справа от второго? [a, b] >> [c, d] истинно, если a > d.
seg &< segbooleanРазве первое seg не простирается вправо от второго? [a, b] &< [c, d] истинно, если b <= d.
seg &> segbooleanНе расширяется ли первое seg влево от второго? [a, b] &> [c, d] истинно, если a >= c.
seg = segbooleanРавны ли два seg?
seg && segbooleanПерекрываются ли два seg?
seg @> segbooleanСодержит ли первое seg второе?
seg <@ segbooleanЯвляется ли первое 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 для примера.