Em idiomas que não permitem sublinhados em constantes inteiras, é uma boa prática criar uma constante para 1 bilhão?


39

Em idiomas que não permitem sublinhados em literais inteiros , é uma boa ideia criar uma constante para 1 bilhão? por exemplo, em C ++:

size_t ONE_BILLION = 1000000000;

Certamente, não devemos criar constantes para números pequenos como 100. Mas com 9 zeros, é sem dúvida fácil deixar um zero ou adicionar um extra no código como este:

tv_sec = timeInNanosec / 1000000000;
tv_nsec = timeInNanosec % 1000000000;

24
Espero que todos aqui votem em NÃO . Dessa forma, talvez um dia meu banco transfira um bilhão de dólares para minha conta porque um programador não usou uma constante e perdeu zero! :)
Reactgular

43
Por que não criar constantes para pequenos números? O que significa 100? A menos que haja algum contexto, é um número mágico.
Allan

4
@MathewFoscarini Em geral, os erros podem ocorrer de qualquer maneira. Mas quando se trata do seu banco, os erros sempre vão contra você.
Emory 24/05

23
Considere escrever 1e9, 10^9ou 1_000_000_000se o idioma que você estiver usando o suportar.
hammar 24/05

Respostas:


33

A maioria dos idiomas apresenta algum tipo de notação exponencial. Um milhão é 1e6(significando 1 vezes 10 à potência de 6). Isso basicamente resolve o problema ainda melhor do que a maioria das proposições aqui.

Em muitas linguagens C, a notação científica está definindo um tipo de ponto flutuante , o que é lamentável se você realmente precisa de um int. No entanto, você pode facilmente converter essa constante para evitar conversões implícitas no seu formulário.

n / int(1e9) dividiria por um bilhão.

No seu exemplo, lidando com quantidades físicas (tempo em nanossegundo), eu geralmente me perguntava se número inteiro é o tipo certo. De fato, um ponto flutuante doublepode ser mais adequado ao lidar com quantidades mensuráveis ​​(embora haja casos em que você preferiria long long).


6
Acho que a solução NANOSECONDS_IN_ONE_SECOND é muito mais clara e mais puro
Thomas Bonini

1
A pergunta era sobre liberais inteiros e proponho usar a notação científica. Fazer isso no local ou definir uma constante é uma questão de estruturar o código que não foi solicitado na pergunta. Definindo uma constante acrescenta abstração limitado, eu iria escrever uma função de conversão / macro para conseguir uma melhor abstração
wirrbel

1
converter um dobro muito grande para um int não arriscaria os problemas típicos de diferença de arredondamento dos números de ponto flutuante?
26513 Philipp

com tipos inteiros de precisão normais, isso não deve ser um problema, desde que você use um float de precisão dupla para converter. você está certo ao usar valores do long longintervalo.
Wirrbel #

145

Crie um chamado NANOSECONDS_IN_ONE_SECOND como o que ele representa.

Ou um nome melhor e mais curto, se você puder pensar em um.


58
Eu diria, Nanoseconds_Per_Secondmas esta é, na minha opinião, a resposta correta.
KChaloux

8
@ Matthew Eu não entendo o seu ponto. Não há nada de errado em dizer milímetros por metro. Você pode estar sugerindo que é redundante, nesse nanossegundo SIGNIFICA um bilhão de frações de segundo, mas não há nada de errado em declará-lo novamente. É como dizer que 1 + 1 = 2 "x por y" continua a fazer mais sentido quando x e y são disjuntos, como "unidades por meia dúzia" ou "nanossegundos por milissegundo"
Mark Canlas

7
@MathewFoscarini Na verdade, não, neste contexto, não é. Se fosse, uma constante nomeada NANOSECONDSnão teria sentido, pois você não pode dizer a que deve se aplicar. Da mesma forma, NANOSECONDS_PER_MICROSECONDé uma constante válida semelhante que faz sentido.
Izkata 24/05

5
@MathewFoscarini, "milímetros por metro" é uma maneira de remover a unidade na conversão para obter o valor bruto. 1mm/1m = 1000, que é exatamente o ponto do que está sendo feito aqui.
ZzzzBov

11
Por que tanta digitação? NS_PER_SECdeve ser óbvio para quem deveria lidar com nanossegundos.
Rex Kerr #

67

As constantes são destinadas a dar significado aos números. Não há nenhum significado adicional em ONE_BILLIONpara 1000000000. Na verdade, isso fica mais confuso, porque em diferentes idiomas naturais, um bilhão significa algo diferente (mil milhões ou milhões)! Se você quiser escrever mais curto, há uma boa chance de sua linguagem de programação permitir o uso de notação científica, ou seja 1e9. Caso contrário, eu concordo com @JohnB, que esse número realmente significa o número de nanossegundos em um segundo, então nomeie isso.


9
É bom apontar que bilhões em diferentes idiomas significam diferentes quantidades de zeros.
Frozenkoi 24/05

3
sugeriria a mudança de idiomas regulares para idiomas naturais. regular significa outra coisa ...
jk.

Diferentes interpretações de "bilhões" em idiomas são um ponto tão bom! Por que não posso votar sua resposta duas vezes!
DSF

3
Você não precisa de idiomas diferentes. Você nem precisa de países diferentes. No inglês britânico, "bilhão" significa algo diferente antes e depois de 1974 nas comunicações oficiais (mídia de massa e governo), e ambos os usos ainda existem.
Jörg W Mittag

1
" Não há qualquer significado adicional no ONE_BILLION para 10000000000. Eu discordo (Dica: Eu deliberadamente mal interpretado você e acrescentou mais um zero; teria notado se não tivesse mencionado isso?)..
Keith Thompson

27

Para um ou dois usos, eu usaria a convenção:

tv_sec = timeInNanosec / (1000 * 1000 * 1000);
tv_nsec = timeInNanosec % (1000 * 1000 * 1000);

É perfeitamente auto-explicativo, é compilado para uma constante e é difícil de estragar.

Além disso, é muito útil em casos como:

var Time = 24 * 60 * 60;

onde é fácil ver que estamos falando de um dia em segundos.


Isto é o que eu costumo fazer. Também tem a vantagem de não esquecer que defini NANOSECONDS_IN_ONE_SECOND ontem e defini NANOSECONDS_PER_SECOND hoje. E talvez ONE_AMERICAN_BILLION amanhã.
Thomas Padron-McCarthy

Certamente 'SecondsInOneDay = 24 * 60 * 60' ainda é mais fácil?
JBRWilkinson

@JBRWilkinson certeza, meu trecho inicial era usar uma classe instance.Time = ..., mas então eu o emburreci ...
Sklivvz

3
Em C ou C ++, (1000 * 1000 * 1000)é do tipo int, que requer apenas 16 bits, para que possa estourar. Você pode escrever (1000L * 1000L * 1000L)para evitar isso.
amigos estão dizendo sobre keith thompson

Eu faço muito isso. Funciona muito bem.
vy32

10

O comprimento do valor não é o que define se uma constante é necessária ou não.

Você usa constantes para evitar números mágicos , não para digitar.

Por exemplo, estas são constantes perfeitamente válidas:

public static final int CLOSE_CURSORS_AT_COMMIT = 1;
public static final int CONCUR_READ_ONLY = 2;
public static final int CONCUR_UPDATABLE = 3;
public static final int FETCH_FORWARD = 4;
public static final int FETCH_REVERSE = 5; 
public static final int FETCH_UNKNOWN = 6;
public static final int HOLD_CURSORS_OVER_COMMIT = 7;
public static final int TYPE_FORWARD_ONLY = 8;
public static final int TYPE_SCROLL_INSENSITIVE = 9;
public static final int TYPE_SCROLL_SENSITIVE = 10;

Usar:

public static final int NANOSECS_PER_SECOND = 1000000000;

(as amostras de código estão em Java, traduzem para o seu idioma favorito)


3
+1 Os números nomeados são quase inúteis. O objetivo das constantes é dar sentido a esses números. O que eles representam? O que eles estão contando, limitando ou formalmente nomeado coeficiente? Não é o valor da contagem.
JustinC


2
Esses são exemplos terríveis de constantes válidas. Eles deveriam ter sido enums, exceto que foram criados antes de enums.
Christoffer Hammarström

@ ChristofferHammarström Eles foram realmente criados antes das enumerações, fazem parte da classe ResultSet, no pacote SQL do Java SDK.
Tulains Córdova

2
@ ChristofferHammarström Eles são ruins porque agora temos enums, mas não por sermos sem sentido. O enum não existia quando essas classes foram criadas e, para diferenciar opções mutuamente exclusivas, como FETCH_FORWARD e FETCH_REVERSE, está dando a eles um valor diferente. O valor não importa, apenas o fato de serem diferentes.
Tulains Córdova

8

Um bilhão americano ou europeu?

(ou em termos técnicos, um bilhão em pequena ou longa escala - um é de 1000 milhões, o outro é um milhão).

Dada essa confusão, então eu diria que sim - faz sentido defini-la uma vez e continuar com ela, da mesma forma se aplica a qualquer constante em que você precisa concordar com a definição - defina-a uma vez.


17
"Um bilhão americano ou europeu?" - "O quê? Eu não sei disso! Ahhhhh !!!!"
Tesserex 25/05

Pelo menos no Reino Unido, adotamos há muito tempo os 1e9 bilhões.
Jack Aidley

1
@ Tesserex - bem, você tem que saber essas coisas quando é rei, sabe.
Gbjbaanb

5

Razões para não

Primeiro, aqui está uma razão para não escrever sublinhados ou usar qualquer truque para simulá-lo: torna as constantes mais difíceis de encontrar no código. Suponha que algum programa exiba, em algum lugar de sua operação, o valor codificado 1500000 para algum parâmetro. Quero saber onde isso realmente ocorre no código-fonte do programa, por isso espero o código 1500000e não encontro nada. Por quê? Pode estar em hexadecimal (mas por que, para um número decimal tão redondo). Sem o meu conhecimento, a constante é realmente escrita como 1_500_000. Eu precisava do regex 1_?500_?000.

Caracteres orientadores no comentário

Só porque um tipo de auxílio visual não está disponível, ou não queremos usá-lo pelo motivo acima, não significa que não possamos tirar proveito das duas dimensões do arquivo de texto para criar um auxílio visual alternativo:

foo = bar / 1000000000;
//           --^--^--^  

Com isso, podemos facilmente nos convencer de que existem três grupos de três zeros. No entanto, ainda podemos 1000000000encontrar e encontrar o código-fonte .

Coloração de sintaxe

Um editor de texto com coloração de sintaxe programável pode ser feito para grupos de dígitos de cores em constantes numéricas com cores alternadas para melhor legibilidade. Não precisamos fazer nada no código.

Pré-processamento: C, C ++, Objetivo C

Agora, se realmente queremos vírgulas entre dígitos, em C e C ++, podemos usar algum pré-processamento:

/* Four digit base TH-ousand constant macro */
/* Condensed using Horner's rule */
#define TH(A,B,C,D) ((((((A) * 1000) + (B)) * 1000) + (C)) * 1000 + D)

tv_sec = nanoseconds / TH(1,000,000,000)

Funciona para números como TH(1,234,567,890).

Uma macro semelhante ao TH também pode trabalhar com colagem de token em vez de aritmética. No pré-processador C, o ##operador binário ("pasta de token") pode ser usado em um corpo de macro para colar dois operandos em um único token. Um ou ambos os operandos podem ser argumentos de macro. A desvantagem aqui (criando um risco para nós) é que, se a catenação resultante não for um token válido, o comportamento será indefinido.

#define TOK4(A, B, C, D) A ## B ## C ## D

Agora

TOK4(1,000,000,000)       /* produces the single token 1000000000 */
TOK4(1,123,000,000.0E+2)  /* produces the single token 1123000000.0E+2 */
TOK4(pr,in,t,f)           /* produces the token printf */
TOK4(#,*,a,b)             /* undefined behavior, #*ab is not valid token syntax */

Existem programas C que colam identificadores e usam os resultados para nomear variáveis ​​e funções globais e são difíceis de trabalhar porque são impermeáveis ​​a ferramentas como GNU id-utils e ctags.


2
+1 por um dos melhores abusos do pré-processador que eu já vi. Eu ainda iria com NSEC_PER_SEC ou algo em produção, no entanto.
213 Victor Victor

Muito quase -1 para abusar do pré-processador :)
um CVn

3

Sim, isso parece uma ideia razoável. Erros DIGIT de um por um são ainda piores do que os infames erros de um por um. No entanto, isso pode criar confusão para outras pessoas (incluindo seu futuro eu) lerem o código.

Um nome mais explicativo como NANOSEC_PER_SEC parece bom, pois adicionaria clareza onde é usado durante o tempo. No entanto, não faz sentido usar em contextos diferentes do tempo e seria impraticável criar 1.000.000.000 separados para cada situação.

O que você realmente quer fazer, por mais bobo que pareça, é 'dividir por segundo'. Isso deixa o NANO_PER, que não é apenas independente do idioma (10 ^ 9 na América e na Europa), mas também independente da situação (sem limitações nas unidades), e é fácil digitar e ler.


é difícil ler este post (parede de texto). Você se importaria de editá -lo em uma forma melhor?
Gnat #

3

Em geral, é uma má idéia usar constantes escalares para conversões de unidades e, se você se encontrar criando constantes para essas coisas, está convertendo em muitos lugares.

Quando você tem uma quantidade de uma unidade (digamos, 10 segundos) e deseja converter para outra unidade (ou seja, nanossegundos); este é precisamente o momento de usar o sistema de tipos do seu idioma para garantir que as unidades sejam realmente dimensionadas conforme você deseja.

Fazer a sua função ter um Nanosecondsparâmetro e fornecer aos operadores de conversão e / ou construtores em que a classe de Seconds, Minutesou que-ter-você. É aqui que o seuconst int ou #defineou 1e9visto em outras respostas pertence.

Isso evita ter variáveis ​​de unidades ambíguas flutuando em torno do seu código; e evita faixas inteiras de bugs de onde a multiplicação / divisão errada foi aplicada, ou já foi aplicada, ou a quantidade era realmente a distância em vez do tempo, ou ...

Além disso, nessas classes, é bom criar uma construção a partir de escalares simples e usar um "MakeSeconds (int)" estático ou semelhante para desencorajar o uso desleixado de números opacos.

Mais especificamente para o seu exemplo, em C ++, verifique Boost.Chrono .


1
+ No mínimo, use um tipo comum com um fator de escala ou deslocamento a partir de uma base, bem como o fuso horário frequentemente difamado.
JustinC

1

Eu, pessoalmente, não consideraria uma boa prática criar uma constante, a menos que precise ser uma constante. Se for em vários lugares e tê-lo definido na parte superior do arquivo para modificação / teste será útil, então absolutamente.

Se é apenas porque é difícil de digitar? então não.

Pessoalmente, se eu obtive o código de outra pessoa com uma constante definida, geralmente considero esse um aspecto importante do código. Por exemplo, tcp mantém temporizadores ativos, número máximo de conexões permitido. Se eu tivesse que depurá-lo, provavelmente prestaria muita atenção desnecessária a ele, tentando descobrir por que / onde está sendo usado.


Entendi a piada, mas se os programadores do banco precisassem fazer uma constante para cada número, você poderia transferir o software seria gigantesco, incontrolável e lento. Eu só podia imaginar como seria isso, imagine ser dito que levaria 3 dias úteis para transferir dinheiro para ... OH MEU DEUS, É ISSO !!!
Simon McLoughlin

Meu banco leva três dias para transferir dinheiro :(
Reactgular

1
Banqueiros @MathewFoscarini usar programadores Excel eles não precisam;)
Mateusz

@ Simon Dependendo do idioma e do compilador, as constantes devem ser otimizadas no código, gerando pouca sobrecarga. Entendo o seu argumento, mas as constantes podem ser usadas sempre que usar um nome em vez de um número mágico ajudaria a legibilidade do código.
24513 Steven

Ler estranho é muito mais um problema do que escrever estranho.
Alb

0

Quando você pensa sobre o motivo de ter escrito "1 bilhão" em vez de "1000000000" no título da sua pergunta, perceberá porque a resposta é sim.


0

Não crie uma constante para seus grandes literais. Você precisaria de uma constante para cada um desses literais, o que é (na minha opinião) uma piada completa. Se você precisar desesperadamente tornar seus literais mais claros sem a ajuda de coisas como destaque de sintaxe, você poderá (embora eu não o faça) criar funções ou macros para tornar sua vida "mais fácil":

#define SPLIT3(x, y, z) x##y##z

int largeNumber1 = SPLIT3(123,456,789);
int largeNumber2 = 123456789;

0

Eu faria isso:

const int Million = 1000 * 1000;
const int Billion = 1000 * Million;

ou

const int SciMega = 1000 * 1000; const int SciGiga = 1000 * SciMega;

Em relação ao número de nanossegundos por segundo: nano é o "inverso" de giga.

Kilo  Mega  Giga   etc.
10^3  10^6  10^9
Milli Micro Nano   etc.
10^-3 10^-6 10^-9

Observe o "Sci" - para científico, como em computadores, os significados de quilo, mega, giga etc. são diferentes: 1024 (2 ^ 10), 1024 * 1024 (2 ^ 20) etc. 2 megabytes não são 2.000.000 bytes .

UPDATE Commenter apontou que existem termos especiais para expoentes digitais de 2: http://en.wikipedia.org/wiki/Mebibyte


"2 megabytes não são 2.000.000 bytes." Pergunte a qualquer fabricante de disco rígido de prato giratório que desejar. (Não é o downvoter, btw.)
um CVn

@michaelkjorling Esta é uma questão de programação, não de ética nos negócios ou de marketing. Eu concordo com discos rígidos, mas esse é um tópico diferente. E ai sobre os votos negativos!
Sr. TA

1
Na verdade, 2 megabytes são 2.000.000 de bytes. 2 Mebibytes são 2.097.152 bytes. Veja en.wikipedia.org/wiki/Mebibyte
vy32

@ vy32 obrigado, nunca ouvi falar disso antes. Atualizarei minha resposta para refletir isso.
Sr. TA

@ Mr.TA, não há problema! Estamos trabalhando duro para tornar a Ciência da Computação em conformidade com as Unidades SI! Junte-se ao clube.
vy32
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.