Почему C# System.Decimal (десятичный) "тратит" биты? - PullRequest
11 голосов
/ 14 июля 2020

Как написано в официальных документах 128 битов System.Decimal заполняются следующим образом:

Возвращаемое значение представляет собой четырехэлементный массив 32-битных подписей. целые числа.

Первый, второй и третий элементы возвращаемого массива содержат младшие, средние и высокие 32 бита 96-битного целого числа.

Четвертый элемент возвращаемого массив содержит масштабный коэффициент и знак. Он состоит из следующих частей:

Биты с 0 по 15, нижнее слово, не используются и должны быть равны нулю.

Биты с 16 по 23 должны содержать показатель степени от 0 до 28, который указывает степень 10 для деления целого числа.

Биты с 24 по 30 не используются и должны быть равны нулю.

Бит 31 содержит знак: 0 означает положительное значение, а 1 означает отрицательное.

Имея это в виду, можно увидеть, что некоторые биты «потрачены впустую» или не используются.

Почему бы, например, не 120 бит целого числа, 7 бит экспоненты и 1 бит знака.

Вероятно, есть веская причина для того, чтобы десятичная дробь была такой, какая она есть. В этом вопросе хотелось бы узнать причину этого решения.

Ответы [ 3 ]

3 голосов
/ 15 июля 2020

На основе комментария Кевина Госсе

Как бы то ни было, десятичный тип, кажется, появился раньше. net. CLR фреймворка. net делегирует вычисления библиотеке oleaut32, и я смог найти следы типа DECIMAL еще в Windows 95

Я поискал дальше и нашел вероятного пользователя код DECIMAL в oleauth32 Windows 95.

Старый Visual Basi c (не на основе NET) и VBA имеют тип sort-of-Dynami c под названием 'Variant'. Там (и только там) вы можете сохранить что-то почти идентичное нашему текущему System.Decimal.

Вариант всегда 128 бит, причем первые 16 бит зарезервированы для значения перечисления из которых тип данных находится внутри Variant.

Разделение оставшихся 112 бит может быть основано на общих архитектурах ЦП в начале 90-х годов или простоте использования для Windows программиста. Кажется разумным не упаковывать экспоненту и подписывать один байт только для того, чтобы иметь еще один байт для целого числа.

Когда. NET был создан существующий (низкоуровневый) код для этого типа, и его операции были повторно используется для System.Decimal.

Ничто из этого не проверено на 100%, и мне бы хотелось, чтобы ответ содержал больше исторических свидетельств, но это то, что я мог бы вместе решить.

1 голос
/ 14 июля 2020

Вот источник C# десятичного . Обратите внимание на методы стиля FCallAddSub. Эти вызовы (недоступные) быстрые реализации этих методов на C ++. работают с 32-битными словами. Если бы использовалось 120 бит, операции ЦП были бы медленнее и сложнее и потребовали бы большого количества битовых масок, чтобы получить интересные дополнительные 24 бита, с которыми тогда было бы трудно работать. Вдобавок это «загрязняет» самые высокие 32-битные флаги и делает невозможными некоторые оптимизации.

Если вы посмотрите на код, вы увидите, что этот простой битовый макет полезен везде. Без сомнения, он особенно полезен в базовом C ++ (и, вероятно, ассемблере).

0 голосов
/ 14 июля 2020

Это потому, что архитектура ЦП основана на 8-битных байтах.

Современные ЦП с момента рождения. NET 32-битные и даже сейчас 64-битные.

Таким образом, регистры ЦП являются 32-битными (4 байта) или 64-битными (8 байтов).

Следовательно, все данные, обрабатываемые ЦП, с начала пути, внутри и из / в память и другие компоненты материнской платы и устройств основаны на этой дихотомии: 8, 16, 32, 64 и даже 128 и более в графическом процессоре или для специального процессора.

Следовательно, CPU для архитектурных и проблемы с производительностью, с которыми необходимо работать, говоря, что просто 32-битные регистры в системах x32 и 64-битные в системах x64.

Фактически,. NET целые числа, имеющие 4 байта, используют половину 64-битный регистр в системах x64.

64-битный ЦП

Руководства разработчика программного обеспечения для архитектур Intel® 64 и IA-32

Современные и общие c ЦП 32- и 64-битные. У них нет 128-битных регистров.

Таким образом, невозможно использовать 120 бит (64 + 56), как вы предлагаете, если только не создать специальную структуру данных, которая будет громоздкой, неуправляемой и контрпродуктивной, медленной, очень низкая производительность.

. NET используйте для кодирования decimal четырех целых чисел по 4 байта для 32-битной совместимости с системами x32, если вы хотите спросить, почему бы не использовать long.

И последнее слово: в тот день, когда мы будем на 128-битных процессорах, возможно, другой десятичный тип будет использовать полностью поддерживаемый изначально регистр для десятичных вычислений, и в этот день мантисса может быть оптимизирована, как вы надеетесь, например, с плавающей точкой и двойной :)

https://referencesource.microsoft.com/#mscorlib / system / decimal.cs

https://github.com/mono/mono/blob/master/mcs/class/corlib/corert/Decimal.cs

О int flags и использование битов, я не знаю, как им управлять, но, пожалуй, могу предположить, что это сделано из соображений оптимизации. Возможно, он использует вычисление ЦП для арифметики с плавающей запятой c и возможностей мантиссы, или нет, я вообще не знаю.

https://en.wikipedia.org/wiki/Floating-point_arithmetic

введите описание изображения здесь

...