Pergunta

Estou escrevendo algoritmos que o trabalho em séries de dados numéricos, onde, por vezes, um valor nas necessidades série a ser nulo. No entanto, porque esta aplicação é desempenho crítico, tenho evitado o uso de tipos anuláveis. Tenho perf testaram os algoritmos para comparar especificamente o desempenho de usar tipos anuláveis ??vs tipos não anuláveis, e na melhor das hipóteses tipos anuláveis ??são 2x mais lento, mas muitas vezes muito pior.

O tipo de dados mais frequentemente usado é o dobro, e atualmente a alternativa escolhida como nulo é Double.NaN. No entanto eu compreendo que este não é o uso exato destinado para o valor NaN, então tenho certeza se existem quaisquer problemas com isso eu não posso prever e qual é a melhor prática seria.

Estou interessado em descobrir o que as melhores alternativas nulos são para os seguintes tipos de dados em particular: double / float, decimais, DateTime, int / long (embora outros são mais que bem-vindo)

Edit: Eu acho que eu preciso esclarecer minhas exigências sobre o desempenho. GB de dados numéricos são processados ??através destes algoritmos de cada vez que leva várias horas. Portanto, embora a diferença entre, por exemplo 10ms ou 20ms é geralmente insignificante, neste cenário ele realmente faz um impacto significativo para o tempo necessário.

Foi útil?

Solução

Bem, se você já descartou Nullable<T>, você é deixado com valores de domínio - ou seja, um número mágico que você tratar como nulo. Enquanto isso não é ideal , não é incomum ou - por exemplo, um monte das principais iguarias código do framework DateTime.MinValue o mesmo nulo. Esta, pelo menos move os danos longe do comum valores ...

Editar para destaque apenas quando há NaN

Então, onde não há NaN, talvez usar .MinValue - mas lembre-se que males acontecer se você acidentalmente uso que mesmo valor ou seja, o mesmo número ...

Obviamente, para dados não assinados você precisará .MaxValue (evitar de zero !!!).

Pessoalmente, eu tento usar Nullable<T> como expressar a minha intenção com mais segurança ... pode haver maneiras de otimizar seu código Nullable<T>, talvez. E também -? No momento em que você verificou para o número mágico em todos os lugares que você precisa, talvez ele não vai ser muito mais rápido do que Nullable<T>

Outras dicas

De certa forma eu discordo Gravell sobre este caso borda específica: uma variável Null-ed é considerado 'não definido', ele não tem um valor. Então o que é usado para sinal que é OK: números até mesmo a magia, mas com números mágicos você tem que levar em conta que um número mágico sempre assombrá-lo no futuro, quando torna-se um valor 'válido' de repente. Com Double.NaN você não tem que ter medo de que: ele nunca vai se tornar um duplo válido. Porém, você tem que considerar que NaN no sentido da sequência das duplas só pode ser usado como um marcador para 'não definido', você não pode usá-lo como um código de erro nas seqüências, bem como, obviamente.

Então o que é usado para marcar 'indefinido': ela tem de ser clara no contexto do conjunto de valores que esse valor específico é considerado o valor para 'indefinido' E isso não vai mudar no futuro.

Se Nullable lhe dar muito problema, uso NaN, ou qualquer outra coisa, contanto que você considerar as conseqüências: o valor escolhido representa 'indefinido' e que vai ficar.

Eu estou trabalhando em um grande projeto que usa NaN como um valor null. Eu não estou totalmente confortável com isso - por razões semelhantes como o seu: não saber o que pode dar errado. Nós não encontrou problemas reais até agora, mas estar ciente do seguinte:

arithmetics NaN -. Embora, na maioria das vezes, "NaN promoção" é uma coisa boa, ele pode não ser sempre o que você espera

Comparação - Comparação de valores fica bastante caro, se você quiser NaN de comparar iguais. Agora, testando carros alegóricos para a igualdade não é de qualquer maneira simples, mas ordenação (a

Código infecção - Eu vejo um monte de código aritmética que requer um tratamento específico de NaN de ser correto. Então você acaba com "funções que aceitam de NaN" e "funções que não fazer" por motivos de desempenho.

Outros não-finitos NaN é nto o valor único não-finito. Deve ser mantido em mente ...

flutuantes exceções de ponto não são um problema quando desativado. Até que alguém lhes. História verdadeira: intialization estática de um NaN em um controle ActiveX. Não soa assustador, até que você altere a instalação usar InnoSetup, que usa um núcleo Pascal / Delphi (?), que tem exceções FPU ativado por padrão. Levei um tempo para descobrir.

Assim, apesar de tudo, nada sério, embora eu prefiro não ter que considerar NaNs que muitas vezes.


Eu usaria tipos anuláveis ??o mais rápido possível, a menos que sejam (provado ser) restrições de performance / ressource. Um caso poderia ser grandes vetores / matrizes com NaNs ocasionais, ou grandes conjuntos de valores individuais nomeadas , onde o comportamento NaN padrão está correto .


Como alternativa, você pode usar um vetor de índice para vetores e matrizes, padrão implementações "matriz escassa", ou um vetor bool / bit separado.

resposta parcial:

Float e Double fornecer NaN (não um número). NaN é um pouco complicado uma vez que, por spec, NaN! = NaN. Se você quer saber se um número é NaN, você vai precisar usar Double.IsNaN ().

Veja também binário ponto flutuante e .NET .

Talvez a diminuição significativa de desempenho acontece quando chamando um dos membros ou propriedades de anuláveis ??(boxe).

Tente usar um struct com o duplo + um revelador booleano se o valor for especificado ou não.

Pode-se evitar alguns dos degradação do desempenho associado com Nullable<T> definindo a sua própria estrutura

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

Se se desejar, pode-se definir construtor, ou a partir de um operador de conversão para T MaybeValid<T>, etc, mas o uso excessivo de tais coisas podem produzir desempenho sub-óptimo. estruturas de campo exposta pode ser eficiente se evita os dados desnecessários de copiar. Algumas pessoas podem desaprovam a noção de campos expostos, mas eles podem ser maciçamente mais eficiente que as propriedades. Se uma função que irá retornar uma T precisaria ter uma variável do tipo T para manter seu valor de retorno, usando um MaybeValid<Foo> simplesmente aumenta em 4 o tamanho da coisa a ser devolvido. Por outro lado, usando um Nullable<Foo> exigiria que a função primeira calcular o Foo e depois passar uma cópia do mesmo para o construtor para o Nullable<Foo>. Além disso, retornando um Nullable<Foo> vai exigir que qualquer código que quer usar o valor retornado deve fazer pelo menos uma cópia extra para um local de armazenamento (variável ou temporária) do tipo Foo antes que ele possa fazer algo útil com ele. Em contraste, o código pode usar o campo Value de uma variável do tipo Foo tão eficiente como qualquer outra variável.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top