Вопрос

Я пишу алгоритмы, которые работают с рядами числовых данных, где иногда значение в ряду должно быть нулевым.Однако, поскольку это приложение имеет решающее значение для производительности, я избегал использования типов с нулевым значением.Я отточил алгоритмы, чтобы специально сравнить производительность использования типов с нулевым значением и типов без нулевого значения, и в лучшем случае типы с нулевым значением в 2 раза медленнее, но часто намного хуже.

Наиболее часто используемый тип данных - double, и в настоящее время альтернативой null является double.NaN.Однако я понимаю, что это не совсем предполагаемое использование значения NaN, поэтому я не уверен, есть ли какие-либо проблемы с этим, которые я не могу предвидеть, и какова была бы наилучшая практика.

Мне интересно выяснить, каковы наилучшие нулевые альтернативы, в частности, для следующих типов данных:double / float, decimal, DateTime, int / long (хотя другие более чем приветствуются)

Редактировать:Я думаю, мне нужно уточнить свои требования к производительности.Гигабайты числовых данных обрабатываются с помощью этих алгоритмов за один раз, который занимает несколько часов.Следовательно, хотя разница, например, между 10 мс или 20 мс обычно незначительна, в данном сценарии она действительно оказывает значительное влияние на затраченное время.

Это было полезно?

Решение

Что ж, если вы исключили Nullable<T>, у вас остаются значения домена - т. е.магическое число, которое вы рассматриваете как null.В то время как это не идеальный вариант, это тоже не редкость - например, большая часть основного кода фреймворка обрабатывает DateTime.MinValue то же самое, что и null.Это, по крайней мере, отдаляет ущерб от общепринятых ценностей...

отредактируйте, чтобы выделить только там, где нет NaN

Так что там, где нет NaN, может быть , использовать .MinValue - но просто помни, какое зло случится, если ты случайно использование то же самое значение, означающее то же число...

Очевидно, что для неподписанных данных вам понадобится .MaxValue (избегайте нуля!!!).

Лично я бы постарался использовать Nullable<T> как более безопасное выражение моего намерения...могут быть способы оптимизировать ваш Nullable<T> возможно, код.И еще - к тому времени, когда вы проверите наличие магического числа во всех необходимых вам местах, возможно, это будет не намного быстрее, чем Nullable<T>?

Другие советы

Я несколько не согласен с Гравеллом в этом конкретном случае edge:переменная с нулевым значением считается "не определенной", у нее нет значения.Так что все, что используется для подачи сигнала, это нормально:даже магические числа, но с магическими числами вы должны учитывать, что магическое число всегда будет преследовать вас в будущем, когда оно внезапно станет "допустимым" значением.С двойным.Нэн, тебе не нужно этого бояться:это никогда не станет действительным дублем.Хотя вы должны учитывать, что NaN в смысле последовательности удвоений может использоваться только как маркер для 'not defined', очевидно, вы также не можете использовать его как код ошибки в последовательностях.

Итак, что бы ни использовалось для обозначения 'undefined':в контексте набора значений должно быть ясно, что это конкретное значение считается значением для 'undefined' И это не изменится в будущем.

Если Nullable доставляет вам слишком много хлопот, используйте NaN или что-то еще, при условии, что вы учитываете последствия:выбранное значение представляет собой "неопределенное", и оно останется.

Я работаю над большим проектом, который использует NaN в качестве null ценность.Меня это не совсем устраивает - по тем же причинам, что и у вас:не зная, что может пойти не так.До сих пор мы не сталкивались с какими-либо реальными проблемами, но имейте в виду следующее:

Наноарифметика - Хотя в большинстве случаев "продвижение по службе NaN" - это хорошо, оно не всегда может быть таким, как вы ожидаете.

Сравнение - Сравнение значений становится довольно дорогостоящим, если вы хотите, чтобы NaN сравнивались одинаково.Теперь проверить поплавки на равенство в любом случае не просто, но упорядочить (a < б) может получиться действительно некрасиво, потому что значения nan иногда должны быть меньше, иногда больше обычных значений.

Заражение кода - Я вижу много арифметического кода, который требует определенной обработки NaN, чтобы быть правильным.Таким образом, в итоге вы получаете "функции, которые принимают NaN" и "функции, которые этого не делают" по соображениям производительности.

Другие не-конечные NaN - это nto единственное конечное значение.Следует иметь в виду...

Исключения с плавающей запятой не являются проблемой, когда они отключены.Пока кто-нибудь не включит их.Правдивая история:Статическая инициализация NaN в элементе управления ActiveX.Звучит не страшно, пока вы не измените установку на использование InnoSetup, которая использует ядро Pascal / Delphi (?), в котором по умолчанию включены исключения FPU.Мне потребовалось некоторое время, чтобы разобраться.

Так что, в общем, ничего серьезного, хотя я бы предпочел не так часто рассматривать NANS.


Я бы использовал типы с нулевым значением как можно чаще, если только они не являются (доказанными) ограничениями производительности / ресурсов.Одним из случаев могут быть большие векторы / матрицы со случайными NAN или большие наборы именованных отдельных значений где поведение NaN по умолчанию является правильным.


В качестве альтернативы вы можете использовать вектор индекса для векторов и матриц, стандартные реализации "разреженной матрицы" или отдельный вектор bool / bit.

Частичный ответ:

Float и Double предоставляют NaN (не число).NaN немного сложнее, поскольку, согласно спецификации, NaN != NaN.Если вы хотите узнать, равно ли число NaN, вам нужно будет использовать Double.isNaN().

Смотрите также Двоичная система с плавающей запятой и .NET.

Возможно, значительное снижение производительности происходит при вызове одного из элементов Nullable или свойств (boxing).

Попробуйте использовать структуру с логическим значением double + a, указывающим, указано ли значение или нет.

Можно избежать некоторого снижения производительности, связанного с Nullable<T> определяя свою собственную структуру

struct MaybeValid<T>
{
    public bool isValue;
    public T Value;
}

При желании можно определить конструктор или оператор преобразования из T Для MaybeValid<T>, и т.д.но чрезмерное использование таких вещей может привести к неоптимальной производительности.Структуры с открытыми полями могут быть эффективными, если избегать ненужного копирования данных.Некоторые люди могут неодобрительно относиться к понятию открытых полей, но они могут быть значительно более эффективными, чем свойства.Если функция, которая вернет T нужно было бы иметь переменную типа T чтобы сохранить его возвращаемое значение, используя MaybeValid<Foo> просто увеличивает на 4 размер возвращаемой вещи.Напротив, используя Nullable<Foo> потребовало бы, чтобы функция сначала вычисляла Foo а затем передайте его копию конструктору для Nullable<Foo>.Далее, возвращая Nullable<Foo> потребует, чтобы любой код, который хочет использовать возвращаемое значение, должен был создать по крайней мере одну дополнительную копию в хранилище (переменное или временное) типа Foo прежде чем он сможет сделать с ним что-нибудь полезное.В отличие от этого, код может использовать Value поле переменной типа Foo примерно так же эффективно, как и любая другая переменная.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top