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

38

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, é bem fácil deixar um zero ou adicionar um extra em código como este:

tv_sec = timeInNanosec / 1000000000;
tv_nsec = timeInNanosec % 1000000000;
    
por Martin C. Martin 24.05.2013 / 18:05
fonte

13 respostas

32

A maioria das linguagens apresenta algum tipo de notação exponencial. Um milhão é 1e6 , (significando 1 vezes 10 para o poder de 6). Isso basicamente resolve o problema ainda melhor do que a maioria das proposições aqui.

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

n / int(1e9) seria dividido em um bilhão.

No seu exemplo, lidando com quantidades físicas (tempo em nanossegundos), eu geralmente me perguntaria se o inteiro é o tipo certo. Na verdade, um ponto flutuante double pode ser mais adequado quando se lida com quantidades mensuráveis (embora haja casos em que você preferiria um long long ).

    
por 25.05.2013 / 11:42
fonte
145

Crie um chamado NANOSECONDS_IN_ONE_SECOND em vez disso, como aquilo que ele representa.

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

    
por 24.05.2013 / 18:21
fonte
67

As constantes destinam-se a dar significado aos números. Não há nenhum significado adicional em ONE_BILLION to 1000000000 . Na verdade, torna-se mais confuso, porque em diferentes línguas naturais, um bilhão significa algo diferente (ou um milhão ou um milhão)! Se você quiser escrevê-lo 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.

    
por 24.05.2013 / 18:22
fonte
27

Para um ou dois usos, 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.

    
por 24.05.2013 / 23:42
fonte
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 evitar a digitação.

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;

Uso:

public static final int NANOSECS_PER_SECOND = 1000000000;

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

    
por 24.05.2013 / 20:18
fonte
8

Um bilhão americano ou europeu?

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

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

    
por 24.05.2013 / 21:13
fonte
5

Razões para não

Primeiramente, aqui está uma razão para não escrever sublinhados ou usar qualquer truque para simulá-lo: isso torna as constantes mais difíceis de encontrar no código. Suponha que algum programa exiba, em algum lugar de sua operação, um valor codificado 1500000 para algum parâmetro. Eu quero saber onde no código-fonte do programa isso realmente ocorre, então eu grep o código para 1500000 e não encontrar nada. Por quê? Pode ser em hexadecimal (mas por que para tal número decimal de uma rodada). 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 pela razão acima, não significa que não podemos tirar proveito das duas dimensões do arquivo de texto para criar um visual alternativo ajuda:

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

Com isso, podemos facilmente nos convencer de que existem três grupos de três zeros. Ainda assim, podemos ainda encontrar o código-fonte para 1000000000 e encontrá-lo.

Coloração da sintaxe

Um editor de texto com coloração de sintaxe programável pode ser feito para colorir dígitos de grupos 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 quisermos algumas 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 a TH também pode trabalhar com token em vez de aritmética. No pré-processador C, o operador ## binário ("token paste") pode ser usado em um corpo de macro para colar dois operandos em um único token. Um ou ambos os operandos podem ser argumentos macro. A desvantagem aqui (criar um risco para nós) é que, se a catenação resultante não for um token válido, o comportamento é 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 */

C programas que colem identificadores e usam os resultados para nomear variáveis globais e funções existem e são horríveis de se trabalhar porque eles são imunes a ferramentas como o GNU id-utils e ctags.

    
por 25.05.2013 / 04:32
fonte
3

Sim, isso parece uma ideia razoável. Os erros DIGIT de um por um são ainda piores que os erros infames off-by-one. Embora possa criar confusão para outras pessoas (incluindo o seu futuro) ler o código.

Um nome mais explicativo como NANOSEC_PER_SEC parece bom, pois acrescentaria clareza onde é usado para o tempo. No entanto, não faz sentido usar em outros contextos além do tempo, e seria impraticável criar um milhão de 1.000.000 para cada situação.

O que você realmente quer fazer, por mais bobo que pareça a princípio, é "dividir por segundo". Isso deixa NANO_PER, que não é apenas independente da linguagem (10 ^ 9 na América e na Europa), mas também independente da situação (sem limitação das unidades), e é fácil de digitar e ler.

    
por 24.05.2013 / 22:08
fonte
3

Em geral, é uma má ideia usar constantes escalares para conversões de unidade, e se você se encontrar fazendo constantes para essas coisas, você está fazendo a conversão em muitos lugares.

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

Faça com que sua função use um parâmetro Nanoseconds e forneça operadores de conversão e / ou construtores nessa classe para Seconds , Minutes ou o que você tem. É aqui que o seu const int ou #define ou 1e9 visto em outras respostas pertence.

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

Além disso, em tais classes é bom fazer construções a partir de escalares simples e usar um "MakeSeconds (int) estático" ou similar para desencorajar o uso desleixado de números opacos.

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

    
por 26.05.2013 / 08:37
fonte
1

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

Se é só porque é estranho digitar? então não.

Pessoalmente, se eu tenho o código de outra pessoa que tinha uma constante definida, geralmente considero isso como um aspecto importante do código. Por exemplo. tcp keep alive timers, número máximo de conexões permitidas. Se eu tivesse que depurá-lo, provavelmente prestaria muita atenção desnecessária a ele tentando descobrir por que / onde está sendo usado.

    
por 24.05.2013 / 18:15
fonte
0

Quando você pensar em por que escreveu "1 bilhão" em vez de "1000000000" no título da pergunta, perceberá por que a resposta é sim.

    
por 25.05.2013 / 01:11
fonte
0

Não crie uma constante para seus grandes literais. Você precisaria de uma constante para cada literal, que é (na minha opinião) uma piada completa. Se você precisa desesperadamente tornar seus literais mais claros sem a ajuda de coisas como realce de sintaxe, você poderia (embora eu não) 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;
    
por 03.06.2013 / 20:08
fonte
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 fins científicos, como em computadores, os significados de kilo, mega, giga etc. são diferentes: 1024 (2 ^ 10), 1024 * 1024 (2 ^ 20), etc. 2 megabytes não é 2.000.000 bytes.

UPDATE O comentador apontou que há termos especiais para expoentes digitais de 2: link

    
por 25.05.2013 / 04:56
fonte