Zero como constante?

15

Eu me deparei com esse idioma de programação recentemente:

const float Zero = 0.0;

que é então usado nas comparações:

if (x > Zero) {..}

Alguém pode explicar se isso é realmente mais eficiente, legível ou sustentável do que:

if (x > 0.0) {..}

NOTA: Posso pensar em outras razões para definir essa constante. Estou apenas pensando em seu uso neste contexto.

NWS
fonte
31
Os desenvolvedores estão planejando portar o código para um universo onde as leis da matemática são diferentes?
precisa saber é o seguinte
6
Sério, não consigo pensar em uma única boa razão para isso. As únicas explicações que posso encontrar são padrões de codificação excessivamente zelosos, ou alguns desenvolvedores que ouviram "números mágicos são ruins", mas não entendem o porquê (ou o que constituiria um número mágico) ...
vaughandroid
@Baqueta -Um universo alternativo? Eu acho que eles já moravam lá! Quanto aos números mágicos, eu concordo, no entanto, uso a regra geral de que Tudo, exceto 0 e 1, deve ser constante.
NWS
1
Se xtiver tipo float, x > 0.0força a promoção para double, o que pode ser menos eficiente. Essa não é uma boa razão para usar uma constante nomeada, apenas para garantir que suas constantes tenham o tipo correto (por exemplo 0f, float(0)ou decltype(x)(0)).
9118 Mike Seymour
1
@ JoSo: para ser justo, o tipo de 13.37não é float, é double. Então, se você queria um float, é concebível que seu tutor estivesse correto. Em alguns contextos (por exemplo, a atribuição a um flutuador) 13.37será implicitamente convertido para o floatque você queria, e em outros contextos (por exemplo, dedução de tipo de modelo) não será, enquanto o static const floatsempre começa como o tipo que você pretendia. Portanto, mais seguro para o tipo. Lembre-se, assim seria 13.37f! Existem outras razões para evitar a macro que não a "segurança de tipo", portanto, é tão provável que o tutor esteja argumentando mal.
Steve Jessop

Respostas:

29

Os possíveis motivos são cache, nomeação ou forçar o tipo

Armazenamento em cache (não aplicável)

Você deseja evitar o custo de criar um objeto durante o ato de comparação. Em Java, um exemplo seria

BigDecimal zero = new BigDecimal ("0.0");

isso envolve um processo de criação bastante pesado e é melhor atendido usando o método estático fornecido:

BigDecimal zero = BigDecimal.ZERO;

Isso permite comparações sem incorrer em um custo repetido de criação, pois o BigDecimal é pré-armazenado em cache pela JVM durante a inicialização.

No caso do que você descreveu, um primitivo está executando o mesmo trabalho. Isso é amplamente redundante em termos de cache e desempenho.

Nomeação (improvável)

O desenvolvedor original está tentando fornecer uma convenção de nomenclatura uniforme para valores comuns em todo o sistema. Isso tem algum mérito, especialmente com valores incomuns, mas algo tão básico quanto zero só vale a pena no caso do cache anterior.

Forçando o tipo (provavelmente)

O desenvolvedor original está tentando forçar um tipo primitivo específico para garantir que as comparações sejam convertidas no tipo correto e possivelmente em uma escala específica (número de casas decimais). Tudo bem, mas o nome simples "zero" provavelmente é um detalhe insuficiente para este caso de uso, com ZERO_1DP sendo uma expressão mais apropriada da intenção.

Gary Rowe
fonte
2
+1 para forçar o tipo. Acrescentarei isso em linguagens como C ++ que permitem a sobrecarga do operador, definir uma constante e usar typedefmanteria o tipo da variável em exatamente um local e permitiria a alteração sem precisar alterar o código.
Blrfl
3
Forçar o tipo provavelmente não é o que eles estavam tentando, no entanto, esta é a melhor explicação de por que isso poderia ser feito!
NWS
7
Para forçar o tipo, provavelmente prefiro usar 0.0f.
Svish
Às vezes, o tipo de forçar pode ser útil no vb.net, onde a execução de operadores bit a bit em bytes gera um resultado em bytes. Dizer byteVar1 = byteVar2 Or CB128parece um pouco melhor do que byteVar1 = byteVar2 Or CByte(128). Obviamente, ter um sufixo numérico adequado para bytes seria melhor ainda. Como o C # promove os operandos de bit a bit para os operadores, intmesmo quando o resultado é garantido para caber em um byte, o problema não é tão relevante lá.
supercat 11/07/12
Não tenho certeza de ter o nome constante como Zero para '0', mas às vezes ajuda na legibilidade do código; por exemplo, ter essa constante para Zero - "ROOT_TYPE_ID = 0" vai ajudar a escrever uma declaração como se {..} (id = ROOT_TYPE_ID!)
Tecnologia Junkie
6

É por causa do "Tooling Nagging"

Uma possível razão pela qual não vejo a lista aqui é porque muitas ferramentas de qualidade sinalizam o uso de números mágicos . Muitas vezes, é uma prática ruim ter números mágicos lançados em um algoritmo sem torná-los claramente visíveis para alterações posteriormente, especialmente se eles forem duplicados em vários locais do código.

Portanto, embora essas ferramentas tenham razão ao sinalizar esses problemas, elas geralmente geram falsos positivos para situações em que esses valores são inofensivos e provavelmente mais estáticos, ou apenas valores de inicialização.

E quando isso acontece, às vezes você enfrenta a escolha de:

  • marcá-los como falsos positivos, se a ferramenta permitir (geralmente com um comentário especialmente formatado, o que é irritante para as pessoas que NÃO usam a ferramenta)
  • ou extrair esses valores para constantes, importando ou não.

Sobre o desempenho

Depende da linguagem, eu acho, mas isso é bastante comum em Java e não tem impacto no desempenho, pois os valores são incorporados no tempo de compilação se forem constantes reais static final. Não teria impacto em C ou C ++ se elas fossem declaradas como constantes ou mesmo como macros de pré-processador.

haylem
fonte
5

Isso pode fazer sentido, pois define explicitamente Zeropara ser do tipo float.

Pelo menos em C e C ++, o valor 0.0é do tipo double, enquanto o equivalente floaté 0.0f. Então, supondo que xvocê compare também é sempre um floatditado

x > 0.0

enquanto, na verdade, promova xpara doublecorresponder ao tipo 0.0que pode levar a problemas (principalmente nos testes de igualdade). A comparação sem conversão seria, obviamente,

x > 0.0f

que faz o mesmo que

float Zero = 0.0; // double 0.0 converted to float  
x > Zero

No entanto, acho que seria muito mais útil habilitar avisos de conversões no compilador, em vez de fazer com que os usuários escrevessem códigos estranhos.

Benjamin Bannier
fonte
1

Primeiro de tudo, aqui zero é definido como float, não int. Obviamente, isso não afeta nada na comparação, mas em outros casos, quando essa constante é usada, pode fazer diferença.

Não vejo outra razão pela qual Zeroseja declarada uma constante aqui. É apenas um estilo de codificação, e é melhor seguir o estilo, se ele for usado em qualquer outro lugar desse programa.

superM
fonte
1

É quase certamente exatamente tão eficiente durante a execução (a menos que seu compilador seja muito primitivo) e levemente menos eficiente durante a compilação.

Quanto a ser mais legível do que x > 0... lembre-se de que existem pessoas que honestamente, genuinamente, pensam que COBOL foi uma ótima idéia e um prazer trabalhar com ele - e também existem pessoas que pensam exatamente o mesmo sobre C. até que existem alguns programadores com a mesma opinião sobre C ++!) Em outras palavras, você não terá um acordo geral sobre esse ponto e provavelmente não vale a pena brigar.

Kilian Foth
fonte
0

[é] isso é realmente mais eficiente, legível ou sustentável do que:

if (x > 0.0) {..}

Se você estava escrevendo código genérico (isto é, não específico do tipo), então é muito possível. Uma zero()função pode ser aplicada a qualquer tipo algébrico ou qualquer tipo que seja uma adição de grupo. Pode ser um número inteiro, pode ser um valor de ponto flutuante, pode até ser uma função se sua variável for, digamos, uma função dentro de algum espaço linear (por exemplo, x é uma função linear da forma z -> a_x * z + b_x) e, em seguida, zero()fornece à função a e b, sendo ambos zero()do tipo subjacente.

Então, você esperaria esse código em, digamos, C ++ possivelmente (embora um zero()AFAIK não seja muito comum), ou em Julia, e talvez em outros idiomas.

einpoklum
fonte