Multiplos de 3 de 1 a 100

22 respostas
S

Ola pessoal estou a estudar as apostilas da caelum e tou com duvidas neste exercicio que axo que nao fiz da melhor maneira e agradecia que me explicassem melhor se possivel obrigado.

class MultiplosTres {
	public static void main(String args[]){
	     int i;
	     
	     for (i = 1; i < 100; i++){
	      i = i + 2;
            
	     	System.out.println(i);
	     }
	     	
	}
}

22 Respostas

J

Você quer um algoritmo melhor para imprimir os múltiplos de 3 entre 1 e 100?
Eu usaria módulo.

xandevieira
if(i%3==0){
				System.out.println("Numero " + i +" é multiplo de 3 ");
			}
rodpuc

O código do rdgc é o mais eficiente. Por módulo tb está correto, mas vc faz mais cálculos e ainda tem um if. Não q seja o fim do mundo, mas só p vc entender.

dionat4n

[size=18] Nem tudo é como parecer ser![/size]

Se vocês pretendem deixar o código otimizado ao máximo, devem fazer apenas uma chamada de sistema operacional para imprimir na tela. Para isso precisa armazenar o resultado em memória para depois imprimir apenas uma vez. Utilizar String para isso é inviável em termos de performance, pois ela é imutável. StringBuffer é a classe eficaz para concatenar muitas Strings, pois ela é mutável. StringBuilder faz a mesma coisa, só que previne a concatenação ao objeto de duas ou mais Threads, nesse exemplo não é nececessária pois existe só a Thread padrão que executa o método main().

Eis o código:public static void main(String args[]){ long t1, t2; t1 = System.currentTimeMillis(); StringBuffer sb = new StringBuffer(); String quebraLinha = "\n"; for (int i = 3; i < 10000; i=i+3){ sb.append(i + quebraLinha); } System.out.println(sb.toString()); t2 = System.currentTimeMillis(); System.out.println(t2-t1 + " milisegundos."); }Para computar e imprimir todos múltiplos de 3 de 1 até 10.000 levou-se 234 milisegundos.

Para aquele código inicial:public static void main(String args[]){ long t1, t2; t1 = System.currentTimeMillis(); int i; for (i = 1; i < 100; i++){ i = i + 2; System.out.println(i); } t2 = System.currentTimeMillis(); System.out.println(t2-t1 + " milisegundos."); }Para computar e imprimir todos múltiplos de 3 de 1 até 10.000 levou-se 953 milisegundos.

Para aquele código incrementando de três em três:public static void main(String args[]){ long t1, t2; for (int i = 3; i < 10000; i = i + 3) { System.out.println("Múltiplo de 3: " + i); } t2 = System.currentTimeMillis(); System.out.println(t2-t1 + " milisegundos."); }Para computar e imprimir todos múltiplos de 3 de 1 até 10.000 levou-se 938 milisegundos.

Claro que esses tempos podem variar de acordo com a preempção da Thread que executa o código. Mas pelo que vocês podem ver, imprimir na tela uma vez sequer é muito, muito, muito mais lento do que uma simples otimização de incremento.

maquiavelbona

Sua mensagem está meio certa. Primeiro:

  • Sim, fazer uma só chamada ao SO torna o seu código mais rápido.
  • Agora é quase que falácia dizer que concatenar Strings é mais lento que usar StringBuffer/StringBuilder. Quer saber por que? Aprenda a usar o javap.

Até!

dionat4n

maquiavelbona:

  • Agora é quase que falácia dizer que concatenar Strings é mais lento que usar StringBuffer/StringBuilder.

Se for quase que falácia, então me explique pq esse código com StringBuffer roda em 47ms.
long t1, t2; t1 = System.currentTimeMillis(); StringBuffer s = new StringBuffer(); for (int i = 0; i < 10000; i++) { //47ms s.append(i + " "); } t2 = System.currentTimeMillis(); System.out.println(s); System.out.println(t2-t1 + "ms.");
E me explique pq esse código abaixo que concatena strings roda em 11422ms.
long t1, t2; t1 = System.currentTimeMillis(); String s = ""; for (int i = 0; i < 10000; i++) { //11422ms s += i + " "; } t2 = System.currentTimeMillis(); System.out.println(s); System.out.println(t2-t1 + "ms.");
Como se vê, é concatenação em Strings versus concatenação em StringBuilder.

Ainda não enxerguei nenhuma falácia no que eu disse.

diegosantiviago

:smiley:

ViniGodoy

Você trocou as bolas ao explicar do StringBuffer e do StringBuilder nesse caso. O StringBuffer é sincronizado e previne o acesso concorrente, e o StringBuilder, não. Portanto, corrija os seus exemplos para usar o StringBuilder, não o StringBuffer. Veja o que diz a documentação do StringBuffer:
“As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.”

Na prática, raramente você utilizará o StringBuffer, pois o acesso concorrente a um único buffer raramente faz sentido. A sincronização só previne que o método append() não seja chamada por duas threads simultâneas, porém, ela não garante nada sobre o que acontece entre duas chamadas ao método append. Por exemplo, se o código
strBuf.append("15/09/1980 ").append("log line ");

For executado por duas threads diferentes a saída poderá ser “15/09/1980 log line 15/09/1980 log line” ou poderá ser “15/09/1980 15/09/1980 log line log line”. O que ela não poderá ser (já que o StringBuffer é sincronizado) é "15log/09/li19ne80 15log/09/li19ne80 ".

A solução para isso é sincronizar a classe que contém o StringBuffer, mas nesse caso, a sincronização do buffer em si torna-se desnecessário, e podemos substitui-lo por um stringBuilder.

A concatenação de Strings realmente é mais rápida com essas classes. Ela só não é mais rápida em casos assim:

String nomeCompleto = titulo + nome + sobrenome + complemento;

Que o java irá substituir invariavelmente por:

String nomeCompleto = new StringBuilder(titulo).append(nome).append(sobrenome).append(complemento);

Mas, realmente, dentro de um while o tempo é incomparavelmente menor, como você mesmo demonstrou.

ViniGodoy

Outra coisa que eu notei…

Já que você está usando o StringBuilder, não use a contatenação dentro do método append, foi feito na linha 7 do programa:

sb.append(i + quebraLinha);

Dessa forma, você pode voltar a incorrer nos custos que queria evitar. No lugar, use o método append do próprio StringBuilder. Uma característica interessante é que esse método retorna o próprio StringBuilder, o que permite-nos chamar em cadeia:

sb.append(i).append(quebraLinha);

Melhor que isso, só se a Sun tivesse escolhido a palavra add no lugar de append…

dionat4n

Você trocou as bolas ao explicar do StringBuffer e do StringBuilder nesse caso. O StringBuffer é sincronizado e previne o acesso concorrente, e o StringBuilder, não. Portanto, corrija os seus exemplos para usar o StringBuilder, não o StringBuffer. Veja o que diz a documentação do StringBuffer:
“As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.”

Na prática, raramente você utilizará o StringBuffer, pois o acesso concorrente a um único buffer raramente faz sentido. A sincronização só previne que o método append() não seja chamada por duas threads simultâneas, porém, ela não garante nada sobre o que acontece entre duas chamadas ao método append. Por exemplo, se o código
strBuf.append(“1”).append(“2”);

For executado por duas threads diferentes a saída poderá ser 1212 ou poderá ser 1122.

A solução para isso é sincronizar a classe que contém o StringBuffer, mas nesse caso, a sincronização do buffer em si torna-se desnecessário, e podemos substitui-lo por um stringBuilder.

A concatenação de Strings realmente é mais rápida com essas classes. Ela só não é mais rápida em casos assim:

String nomeCompleto = titulo + nome + sobrenome + complemento;

Que o java irá substituir invariavelmente por:

String nomeCompleto = new StringBuilder(titulo).append(nome).append(sobrenome).append(complemento);

Mas, realmente, dentro de um while o tempo é incomparavelmente menor, como você mesmo demonstrou.

Não troquei as bolas não.

Evitar o acesso concorrente para concatenação no objeto é a mesma coisa que evitar a concatenação ao objeto de duas ou mais Threads ( ao mesmo tempo! esqueci de escrever isso… :stuck_out_tongue: )

dionat4n

ViniGodoy:
Outra coisa que eu notei…

Já que você está usando o StringBuilder, não use a contatenação dentro do método append, foi feito na linha 7 do programa:

sb.append(i + quebraLinha);

Dessa forma, você pode voltar a incorrer nos custos que queria evitar. No lugar, use o método append do próprio StringBuilder. Uma característica interessante é que esse método retorna o próprio StringBuilder, o que permite-nos chamar em cadeia:

sb.append(i).append(quebraLinha);

Melhor que isso, só se a Sun tivesse escolhido a palavra add no lugar de append…

Com certeza, eu até iria fazer isso, mas daí ficaria diferente do programa anterior, pois eu queria adicionar strings propriamente dito.

ViniGodoy

Ué, se não trocou as bolas, porque seu código está com o StringBuffer, e não o StringBuilder, quando a documentação diz que é justamente o contrário que se deve fazer?

Sua explicação está trocada sim cara. Leia o Javadoc.

dionat4n

ViniGodoy:
Ué, se não trocou as bolas, porque seu código está com o StringBuffer, e não o StringBuilder, quando a documentação diz que é justamente o contrário que se deve fazer?

Sua explicação está trocada sim cara. Leia o Javadoc.

Viajei total! hauehuaehuea
É verdade, troquei as bolas…
Se bem que quem nomeou essas classes poderia colocar algo mais sugestivo…

Valeu!

maquiavelbona

dionat4n:

Ainda não enxerguei nenhuma falácia no que eu disse.


Javap -verbose do trecho do código usando String:

16:	iload	6
   18:	sipush	10000
   21:	if_icmpge	56
   24:	aload	5
   26:	new	#5; //class java/lang/StringBuilder
   29:	dup
   30:	invokespecial	#6; //Method java/lang/StringBuilder."<init>":()V
   33:	iload	6
   35:	invokevirtual	#7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   38:	ldc	#8; //String  
   40:	invokevirtual	#9; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   43:	invokevirtual	#10; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   46:	invokevirtual	#11; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
   49:	pop
   50:	iinc	6, 1
   53:	goto	16

Agora o trecho do código usando StringBuilder.

11:	iload	6
   13:	sipush	10000
   16:	if_icmpge	52
   19:	new	#4; //class java/lang/StringBuilder
   22:	dup
   23:	invokespecial	#5; //Method java/lang/StringBuilder."<init>":()V
   26:	aload	5
   28:	invokevirtual	#6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   31:	iload	6
   33:	invokevirtual	#7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   36:	ldc	#8; //String  
   38:	invokevirtual	#6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   41:	invokevirtual	#9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   44:	astore	5
   46:	iinc	6, 1
   49:	goto	11

Agora vamos com as considerações:
-testes de microscópio nada inferem. Sua máquina poderia estar rodando algo em algum momento;
-você viu em algum lugar que o código concatena Strings diretamente? Ou será que o compilador foi esperto o suficiente para saber que tinha um loop concatenando String?

Até!

dionat4n

Eu executei diversas vezes o mesmo código para me certificar disso. Se duvida, faça isso.

Nesse link abaixo esclarece tudo:
“In conclusion, StringBuffer concatenation is significantly faster than String concatenation. Obviously, StringBuffers should be used in this type of operation when possible. If the functionality of the String class is desired, consider using a StringBuffer for concatenation and then performing one conversion to String.”
http://www.javaworld.com/javaworld/jw-03-2000/jw-0324-javaperf.html

maquiavelbona

http://nicklothian.com/blog/2005/06/09/on-java-string-concatenation/

http://java.sun.com/developer/JDCTechTips/2002/tt0305.html

http://www.precisejava.com/javaperf/j2se/StringAndStringBuffer.htm

dionat4n

Os artigos se contradizem…

Obrigado pela insistência, na próxima terei que analisar melhor isso.

B

dionat4n:
Eu executei diversas vezes o mesmo código para me certificar disso. Se duvida, faça isso.

Nesse link abaixo esclarece tudo:
“In conclusion, StringBuffer concatenation is significantly faster than String concatenation. Obviously, StringBuffers should be used in this type of operation when possible. If the functionality of the String class is desired, consider using a StringBuffer for concatenation and then performing one conversion to String.”
http://www.javaworld.com/javaworld/jw-03-2000/jw-0324-javaperf.html

Em 2000 isso era verdade.

Hoje em 2009, muita coisa foi otimizada no Java 6, concatenação de Strings é uma delas. Não há mais tanta diferença.

dionat4n

Bruno Laturner:
dionat4n:
Eu executei diversas vezes o mesmo código para me certificar disso. Se duvida, faça isso.

Nesse link abaixo esclarece tudo:
“In conclusion, StringBuffer concatenation is significantly faster than String concatenation. Obviously, StringBuffers should be used in this type of operation when possible. If the functionality of the String class is desired, consider using a StringBuffer for concatenation and then performing one conversion to String.”
http://www.javaworld.com/javaworld/jw-03-2000/jw-0324-javaperf.html

Em 2000 isso era verdade.

Hoje em 2009, muita coisa foi otimizada no Java 6, concatenação de Strings é uma delas. Não há mais tanta diferença.

Tem razão… Mas o que rodei aqui foi no Java 6, estranho.

Edu22SNT

Bom dia,

Essa é uma das idéias que podemos usar com o for.

public class ImprimirMultiplosDe3For {

public static void main(String[] args) {
	
	
	for (int c = 3; c < 100; c=c+3){
		System.out.println(c);
	}
}

}

E essa é uma das idéias que podemos usar com o while.

public class ImprimirMultiplosDe3While {
public static void main (String [] args){

int c = 3;
	int e = 100;
	
	while (c <= e){
		System.out.println(c);
		c=c+3;	
	}
}

}

Att,
Eduardo Monteiro de Andrade
http://eduardomandrade.blogspot.com.br/

ViniGodoy

Edu22SNT:
Bom dia,

Essa é uma das idéias que podemos usar com o for.

Por favor, não ressuscite tópicos antigos para repetir o que já foi dito.
Sua solução já está nesse mesmo tópico, aqui:

Se for ressuscitar tópicos, deixe claro que está fazendo isso, e faça apenas se tiver uma solução inédita e mais eficiente para o problema.
Evite simplesmente responder a dúvida como se ela fosse postada ontem, pois isso confunde outros respondentes.

Além disso, ao postar tópicos, por favor, use a tag code, como descrito aqui:
http://www.guj.com.br/bookmarks/list/17737.java

R

Não sei qual é a intensão do exercício e não entendi sua dúvida… mas vai um exemplo:

for (int i=3; i<100; i=i+3) {
            System.out.println("Múltiplo de 3: " + i);
        }
Criado 12 de março de 2009
Ultima resposta 12 de mar. de 2009
Respostas 22
Participantes 11