Por que escrever 1.000.000.000 como 1000 * 1000 * 1000 em C?


142

No código criado pela Apple, existe esta linha:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

Existe algum motivo para expressar 1,000,000,000como 1000*1000*1000?

Por que não 1000^3?


45
Clareza e legibilidade do código. Você não pode colocar, ou 'como separadores em C, então a melhor coisa a seguir é calcular o valor de uma multiplicação. ^ é um operador não relacionado no OR exclusivo de C.
Iwillnotexist Idonotexist

54
especialmente utilizado para durações como: 2 * 60 * 60 .. é fácil perceber que é para duas horas ..
idali

53
Por um lado eu suspeito 1000000000 não é válido sintaxe
paparazzo

15
A propósito, as linguagens de programação modernas têm uma maneira alternativa de escrever o mesmo, por exemplo, no Swift 1_000_000_000. No entanto, com constantes de tempo, isso é mais difícil. É mais legível escrever 30 * 60(30 minutos em segundos) do que escrever 1800. Na verdade, existem idiomas que permitem que você escreva unidades, por exemplo meters, permitindo que você se proteja contra atribuições ruins.
Sulthan

29
^é um XOR, não um expoente ou operador de energia.
3Dave

Respostas:


200

Um motivo para declarar constantes de maneira multiplicativa é melhorar a legibilidade, enquanto o desempenho em tempo de execução não é afetado. Além disso, para indicar que o escritor estava pensando de maneira multiplicativa sobre o número.

Considere isto:

double memoryBytes = 1024 * 1024 * 1024;

É claramente melhor que:

double memoryBytes = 1073741824;

como este último não parece, à primeira vista, o terceiro poder de 1024.

Como Amin Negm-Awad mencionou, o ^operador é o binário XOR. Muitos idiomas não possuem o operador interno de exponenciação em tempo de compilação, daí a multiplicação.


13
E em idiomas que possuem um operador de exponenciação, não é necessariamente '^'. No Fortran, por exemplo, é '**'.
jamesqf

4
Você também deve incluir um link apontando para a ressalva importante, dada na resposta abaixo, em @chux: stackoverflow.com/a/40637622/1841533 (especialmente quando o OP marcou "c", o que é muito suscetível a esta operação lateral parece ter todos os termos limitados a um tipo menor e, portanto, a multiplicação pode estourar o problema). securecoding.cert.org/confluence/display/c/… pode ajudar a evitar aqueles no caso geral?
Olivier Dulac

4
Também devemos observar que o cálculo é feito em tempo de compilação. O Padrão C exige que a implementação seja capaz de calcular expressões constantes em tempo de compilação para vários recursos da linguagem e podemos assumir com segurança que é verdade quando uma expressão constante é usada como neste exemplo.
ouah

13
Armazenando quantidade de memória como um dobro? Isso parece ser uma fonte potencial de erro.
JAB

7
@supercat Estou ciente disso, mas usando double você pode ter um caso em que, digamos, você deseja uma parte do intervalo de memória, divide xpara obter o tamanho do subintervalo ... e de repente você tem um fracionário byte, o que pode exigir lógica adicional para compensar.
JAB

73

Por que não 1000^3?

O resultado de 1000^3é 1003. ^é o operador bit-XOR.

Mesmo que não lide com o próprio Q, acrescento um esclarecimento. x^yse não sempre avaliar a x+ycomo faz no exemplo do questionador. Você tem que xor todo. No caso do exemplo:

1111101000 (1000₁₀)
0000000011 (3₁₀)
1111101011 (1003₁₀)

Mas

1111101001 (1001₁₀)
0000000011 (3₁₀)
1111101010 (1002₁₀)

3
senhor, não sei como 1003 ^ 3 é 1003. O Google e o Mac Calculator mostram 1000 ^ 3 = 1.000.000.000. você pode explicar?
Mahesh

57
O ^operador significa XOR em C / C ++ / Objective-C etc. Nas calculadoras, geralmente significa potência x-to-y.
Tamás Zahola 16/11

5
Bah, os bits de 1000 e 3 não se sobrepõem. Isso parece tão errado.
Yakk - Adam Nevraumont

19
Os bits se sobrepõem. Mas não os 1s. : -]
Amin Negm-Awad 16/11/16

6
@Yakk: na verdade, parece tão errado! ... Espero que muitas pessoas não vão pensar que "A ^ B" sempre dá A + B (mas temo algum poder ...)
Olivier Dulac

71

Existem razões para não usar 1000 * 1000 * 1000.

Com 16 bits int, 1000 * 1000estouros excessivos. Portanto, o uso 1000 * 1000 * 1000reduz a portabilidade.

Com 32 bits int, a primeira linha de código a seguir é excedida.

long long Duration = 1000 * 1000 * 1000 * 1000;  // overflow
long long Duration = 1000000000000;  // no overflow, hard to read

Sugira que o valor do lead corresponda ao tipo de destino para legibilidade, portabilidade e correção.

double Duration = 1000.0 * 1000 * 1000;
long long Duration = 1000LL * 1000 * 1000 * 1000;

Também poderia usar a enotação simples para valores que são exatamente representáveis ​​como a double. É claro que isso leva a saber se doublepode representar exatamente o valor do número inteiro - algo preocupante com valores maiores que 1e9. (Veja DBL_EPSILONe DBL_DIG).

long Duration = 1000000000;
// vs.
long Duration = 1e9;

5
Observação muito importante! securecoding.cert.org/confluence/display/c/… pode ajudar em muitos casos?
Olivier Dulac

2
A doublepode representar exatamente todos os números inteiros até 2 ^ 53 ≈ 9e15.
Edgar Bonet

3
@ EdgarBonet É verdade que o binary64 pode representar um número inteiro até cerca de 9e15. Mas C não especifica o doubleuso de binary64, mesmo que seja muito usado. De acordo com a especificação C, valores de até 1e9 ou mais são exatamente representáveis. Depende se você deseja codificar para especificar ou confiar na prática comum.
chux - Restabelece Monica

4
@ Patrick Ambos 1000e 1000000000000são constantes inteiras . Cada um independentemente com o tipo selecionado de int, longou long long. O compilador usa o primeiro tipo daqueles 3 nos quais a constante inteira se encaixa. 1000 * 1000 * 1000 * 1000é feito com intmatemática como cada 1000um em int. O produto está cheio de 32 bits int. 1000000000000 é certamente representável como um long long(ou possivelmente mais estreito) - sem transbordamento. O tipo do alvo long long Durationnão afeta esse "lado direito da desatreminação =".
chux - Restabelece Monica

2
Colocar o tipo mais amplo primeiro na multiplicação é importante. Com 16 bits int, long x = 1000 * 1000 * 1000L;iria transbordar, enquanto long x = 1000L * 1000 * 1000;não.
ex nihilo 24/07

51

Para legibilidade.

Colocar vírgulas e espaços entre os zeros ( 1 000 000 000ou 1,000,000,000) produziria um erro de sintaxe, e ter 1000000000no código dificulta a visualização exata de quantos zeros existem.

1000*1000*1000torna aparente que é 10 ^ 9, porque nossos olhos podem processar os pedaços mais facilmente. Além disso, não há custo de tempo de execução, porque o compilador o substituirá pela constante 1000000000.


5
Para sua informação, existe um conceito de separadores de dígitos que aprendi recentemente. O Java já existe há algum tempo e o C # 7.0 pode obtê-lo. Eu gostaria que todos os idiomas tivessem esse recurso atraente. :)
iheartcsharp

1
Dependendo do contexto, o uso 1,000,000,000não produziria um erro de sintaxe, apenas significaria outra coisa. Por exemploCMTimeMakeWithSeconds( newDurationSeconds, 1,000,000,000 )
Ross Ridge

2
O @ JMS10 C # já o possui, se você instalar a versão de visualização do VS15, pode ser escrito como #1_000_000_000
user1306322:

2
Python está ficando _como separador, também :)
Wayne Werner

2
E o C ++ recentemente obteve o 'separador, no C ++ 14, para que você possa usá-lo 1'000'000'000. (Ele foi escolhido porque 1,000,000,000podia ser mal interpretado como o operador vírgula ou 4 parâmetros distintos, e _1_000_000_000é um nome de variável válido (mas provavelmente ruim).)
Justin Time - Reintegrar Monica

27

Para legibilidade. Para comparação, o Java suporta _números para melhorar a legibilidade (proposto pela primeira vez por Stephen Colebourne como resposta à PROPOSTA de Derek Foster: Literais binários para o Project Coin / JSR 334). Alguém escreveria 1_000_000_000aqui.

Em ordem cronológica, do suporte mais antigo ao mais recente:

É um recurso relativamente novo para os idiomas perceberem que eles devem suportar (e então há o Perl). Como na excelente resposta do chux @, 1000*1000...é uma solução parcial, mas abre o programador para que os erros ultrapassem a multiplicação, mesmo que o resultado final seja do tipo grande.


Muitas linguagens de programação modernas têm o mesmo, por exemplo, Swift. Nada de novo.
Sulthan

AFAIK, isso vem do Perl. PL / M usou $ para a mesma finalidade, por exemplo: 0100 $ 0010B
ninjalj 17/11

1
Ele é bastante novo, no entanto. O recurso Java talvez tenha 5 anos. A maioria das outras linguagens que suportam essa sintaxe são bem novas - o Swift em si tem apenas alguns anos de idade. O Python adiciona suporte na 3.6, que ainda não foi lançado.
johncip

2
Ada suporta sublinhados em literais inteiros há 33 anos.
Peter - Restabelece Monica

1
@ djechlin: Tomei a liberdade de adicionar mais informações, aproximadamente em ordem cronológica. Eu estava enganado antes, a julgar pelo tópico Project Coin, Stephen Colebourne provavelmente adotou a idéia de sublinhado em literais inteiros de Fandom e / ou Ruby. Ruby provavelmente pegou a idéia de Perl e Perl de Ada.
Ninjalj 17/11

7

Pode ser mais simples de ler e obter algumas associações com o 1,000,000,000formulário.

Do ponto de vista técnico, acho que não há diferença entre o número direto ou a multiplicação. O compilador irá gerá-lo como um número constante de bilhões de qualquer maneira.

Se você falar sobre o objetivo-c, 1000^3não funcionará porque não existe essa sintaxe para o pow (é xor). Em vez disso, a pow()função pode ser usada. Mas, nesse caso, não será o ideal, será uma chamada de função de tempo de execução, não uma constante gerada pelo compilador.


3

Para ilustrar os motivos, considere o seguinte programa de teste:

$ cat comma-expr.c && gcc -o comma-expr comma-expr.c && ./comma-expr
#include <stdio.h>

#define BILLION1 (1,000,000,000)
#define BILLION2 (1000^3)

int main()
{
        printf("%d, %d\n", BILLION1, BILLION2);
}
0, 1003
$

1
@pjvandehaar Eu não recomendaria aprender um idioma lendo artigos da Wikipedia.
Peter - Restabelece Monica

0

Outra maneira de obter um efeito semelhante em C para números decimais é usar a notação literal de ponto flutuante - desde que um duplo possa representar o número desejado sem perda de precisão.

O IEEE 754 de 64 bits duplo pode representar qualquer número inteiro não negativo <= 2 ^ 53 sem problemas. Normalmente, o duplo longo (80 ou 128 bits) pode ir ainda mais longe. As conversões serão feitas em tempo de compilação, portanto, não haverá sobrecarga de tempo de execução e você provavelmente receberá avisos se houver uma perda inesperada de precisão e você tiver um bom compilador.

long lots_of_secs = 1e9;
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.