Вопрос или проблема
Если я устанавливаю масштабирование 175% в настройках Gnome, значение сохраняется как 1.7518248558044434
в ~/.config/monitors.xml
:
<monitors version="2">
<configuration>
<logicalmonitor>
<x>0</x>
<y>0</y>
<scale>1.7518248558044434</scale>
<primary>yes</primary>
<monitor>
<monitor spec>
<connector>DP-3</connector>
Почему это так? Сначала я думал, что это может быть связано с ошибкой округления числа с плавающей запятой, но 1,75 — одно из тех счастливых чисел, которые можно точно выразить.
Gnome Wayland 43.3
Предустановленные коэффициенты масштабирования (100%, 125% и т. д.) корректируются на ближайшие значения, которые дают целое число виртуальных пикселей до масштабирования как по горизонтали, так и по вертикали для вашего разрешения; судя по вашему значению 1.7518248558044434, это, вероятно, виртуальное разрешение 2192 x 1233, и у вас дисплей 3840 x 2160.
Также интересна причина, почему ширина, которую вы бы вычислили с этим значением 3840/1.7518248558044434 = 2191.9999520937613
, точна только примерно до четырех знаков после запятой; очевидно, масштаб был преобразован из чисел с плавающей запятой одинарной точности (IEEE-754 32-бит). Приближение двойной точности 3840/2192
больше похоже на 1.7518248175182483
, но если преобразовать это значение в одинарную точность и обратно в двойную точность, вы получите точно 1.7518248558044434
. Я сделал это с помощью Python, как предложено в ответе https://stackoverflow.com/a/43405711/60422:
>>> struct.unpack('f', struct.pack('f', 1.7518248175182483))[0]
1.7518248558044434
Стефан Чазелас предлагает соответствующую однострочную команду в Perl:
perl -e 'printf "%.17g\n", unpack "f", pack "f", 1.7518248175182483'
Почему преобразование числа с плавающей точкой в более высокую точность дает десятичное представление с большим количеством цифр, которые бесполезны, — это тип ошибки округления числа с плавающей точкой, на которую намекает вопрос. Внутреннее представление числа с плавающей точкой является двоичным, и поэтому цифры после точки внутри (“двоичной точки”, так как это двоичная система) представляют степень двоичных дробей (1/2, 1/4, 1/8 и так далее). Число, которое может быть выражено в конечном числе знаков в десятичной системе, не обязательно имеет конечное представление в двоичной, и наоборот. Подробнее об этом: https://stackoverflow.com/a/588014/60422
Одинарная точность обычно считается хорошей для около 7 значимых десятичных цифр, и это то, что мы видим здесь.
Чтобы понять, как работает корректировка коэффициента масштабирования, которая приводит к этому числу, функция get_closest_scale_factor_for_resolution
в mutter
вычисляет виртуальную ширину и высоту из коэффициента масштабирования, а затем, если эти значения не являются целыми числами, начиная с рассчитанной ширины, округленной вниз, она пробует целые числа ширины вокруг рассчитанного на обеих сторонах, расширяясь наружу по одному пикселю за раз, пока не найдет ширину, которая дает скорректированный коэффициент масштабирования, который также делает виртуальную высоту целым числом, или пока не сдастся из-за того, что масштаб вышел из диапазона или порога поиска. https://gitlab.gnome.org/GNOME/mutter/-/blob/176418d0e7ac6a0418eea46669f33c8e3b03c4bd/src/backends/meta-monitor.c#L1960
Если вы хотите узнать почему разработчики даже решили округлять коэффициенты масштабирования до целых чисел пикселей, у меня нет ответа на этот вопрос, но я предполагаю, что это обратная совместимость: разработчики привыкли к мониторам с целыми числами пикселей, и поэтому существующее программное обеспечение разработано именно для этого.
Другая теория: рациональное число, которое 1.7518248558044434 является приближением, не 2192/1233, а более простое 240/137 = 1.7518248175182481… (Чтобы получить более близкое рациональное число, нужно увеличивать числитель и знаменатель на значение, превышающее в 1390 раз. И да, десятичные представления кратных 1/137 имеют 8-значный цикл.) Таким образом, для высоты и ширины в пикселях есть несколько возможностей, которые дадут это соотношение, включая 2160 x 1233.
Но, скажете вы, 240/137 близко, но не так уж близко. Другое хорошее приближение — 3673843/2097152. Чтобы получить более близкое рациональное число, вам потребуется числитель и знаменатель, увеличенные в тысячи раз. 1/2097152 равно 2^{-21}. Это указывает на то, что 240/137 было сохранено в двоичном формате с плавающей точкой с достаточным количеством битов для мантиссы: один бит слева и 21 бит справа от двоичной точки. (Эти подсчеты битов не учитывают возможные конечные нули.) Затем это было преобразовано в десятичное значение с гораздо большей точностью, чем в этом двоичном представлении.
Ответ или решение
Почему масштабирование Gnome fractional scaling составляет 1.7518248558044434 вместо 1.75?
Когда вы устанавливаете масштабирование 175% в настройках Gnome, это значение сохраняется как 1.7518248558044434
в файле ~/.config/monitors.xml
. Хотя на первый взгляд кажется, что это может быть связано с ошибкой округления, на самом деле причина более сложна и связана с особенностями представления чисел с плавающей запятой и алгоритмом расчета масштабирования.
Причины различных значений
-
Плавающая запятая и точность: Значение
1.7518248558044434
появляется из-за особенностей работы с плавающей запятой по стандарту IEEE-754. В данном случае, мы имеем дело с представлением чисел в формате одинарной точности (32-бита). Это формат может представлять число примерно с 7 значимыми цифрами, что ведет к некорректностям при переводе чисел между разными системами счисления (например, двоичной и десятичной). -
Алгоритмы масштабирующего фактора: Настройки масштабирования в Gnome должны обеспечивать целые значения, которые дают целое число виртуальных пикселей и для горизонтальной, и для вертикальной осей. Ваша указанная конфигурация «1.7518248558044434» вероятно связана с разрешением 2192×1233 виртуальных пикселей для дисплея 3840×2160.
-
Оптимизация и совместимость: Алгоритм
get_closest_scale_factor_for_resolution
в библиотекеmutter
старается подобрать такие масштабирующие коэффициенты, чтобы они давали четкие значения для виртуальных разрешений до тех пор, пока масштаб не выйдет за пределы допустимого диапазона или порога поиска.
Практические расчеты на Python и Perl
Для анализа значения 1.7518248558044434
на Python можно использовать:
import struct
print(struct.unpack('f', struct.pack('f', 1.7518248175182483))[0])
Аналогичная операция в Perl:
perl -e 'printf "%.17g\n", unpack "f", pack "f", 1.7518248175182483'
Эти конвертации демонстрируют, каким образом небольшая разница в представлении числа может привести к другим значениям при обратной конвертации из одинарной в двойную точность.
Заключение
Масштабирование, отличное от заданного 1.75, может быть результатом алгоритмов, оптимизирующих целые виртуальные пиксели для совместимости с программами, ожидающими целочисленное представление пикселей. Этот подход может также повысить стабильность и предсказуемость работы приложений на различных разрешениях.
Для пользователей, заинтересованных в максимальной точности масштабирования на экранах высокой четкости, такие нюансы являются ключевыми для понимания работы среды на основе Linux. Понимание внутренней работы и ограничений форматов чисел с плавающей запятой также помогает избежать неожиданных результатов и оперировать настройками более осознанно.